文章目录
刷题链接
合并k个有序链表(堆多路归并)
用堆进行多路归并
,时间复杂度 O ( n l o g k ) O(nlogk) O(nlogk)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
typedef pair<int,ListNode*> PIL;
priority_queue<PIL,vector<PIL>,greater<PIL>> heap; // 小根堆
for(auto &c : lists)
if(c) heap.push({
c->val,c});
ListNode *head = new ListNode(-1);
auto cur = head;
while(heap.size())
{
auto t = heap.top();
heap.pop();
ListNode* p = t.second;
cur->next = p;
cur = cur->next;
auto next = p->next;
if(next) heap.push({
next->val,next});
}
cur->next = NULL;
return head->next;
}
};
字符串的排列(有重复)
递归实现排列
class Solution {
public:
vector<string> res;
vector<bool> st;
int n;
string s;
string path;
vector<string> Permutation(string str) {
s = str;
n = s.size();
st = vector<bool>(n);
dfs(0);
return res;
}
void dfs(int u)
{
if(u == n)
{
res.push_back(path);
return;
}
for(int i = 0;i < n;i ++ )
if(!st[i])
{
path.push_back(s[i]);
st[i] = true;
dfs(u + 1);
st[i] = false;
path.pop_back();
while(i + 1 < n && s[i + 1] == s[i]) i ++ ;
}
}
};
next_permutation()
函数返回下一个排列
class Solution {
public:
vector<string> res;
vector<string> Permutation(string str) {
sort(str.begin(),str.end());
do{
res.push_back(str);
}while(next_permutation(str.begin(), str.end()));
return res;
}
};
斐波那契数列(递推)
递推
class Solution {
public:
int Fibonacci(int n) {
if(n <= 1) return n;
int a = 0,b = 1, c;
for(int i = 1;i < n;i ++ )
{
c = a + b;
a = b, b = c;
}
return c;
}
};
最长递增子序列(求具体方案,贪心 + 二分)
贪心 + 二分,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
增加记录方案的dp[i] : 表示下标为i的元素长度为dp[i]。
class Solution {
public:
/**
* retrun the longest increasing subsequence
* @param arr int整型vector the array
* @return int整型vector
*/
vector<int> LIS(vector<int>& arr) {
// write code here
int n = arr.size();
vector<int> q(n + 1); // 贪心二分,q[i]表示长度为i的最小元素是q[i]
vector<int> dp(n); // 记录方案,dp[i]表示下标为i的元素长度是dp[i]
int len = 0;
for(int i = 0;i < n;i ++ )
{
int l = 0,r = len; // 二分找第一个小于arr[i]的数,下一个数即为>=arr[i]
while(l < r)
{
int mid = l + r + 1>> 1;
if(q[mid] < arr[i]) l = mid;
else r = mid - 1;
}
dp[i] = r + 1;
len = max(len,r + 1);
q[r + 1] = arr[i];
}
vector<int> res(len);
//cout << len <<endl;
for(int i = 0;i < n;i ++) cout << dp[i] <<" ";
for(int i = n - 1;len >= 1;i -- ) // 从后往前遍历,在后面的一定是字典序最小的(贪心决定)
if(dp[i] == len){
res[len - 1] = arr[i]; // res下标从0开始,所以要-1
len --;
}
return res;
}
};
在转动过的有序数组中寻找目标值(二分)
二分找分界点,再根据if(target <= A[n - 1])
判断是在前半段还是后半段
class Solution {
public:
/**
*
* @param A int整型一维数组
* @param n int A数组长度
* @param target int整型
* @return int整型
*/
int search(int* A, int n, int target) {
// write code here
int l = 0,r = n - 1;
while(l < r)
{
int mid = l + r >> 1;
if(A[mid] <= A[n - 1]) r = mid;
else l = mid + 1;
}
if(target <= A[n - 1]) r = n - 1; // 后半段
else l = 0, r -- ; // 前半段
while(l < r)
{
int mid = l + r >> 1;
if(A[mid] >= target) r = mid;
else l = mid + 1;
}
if(A[l] != target) return -1;
return l;
}
};
数组中相加和为0的三元组(排序 + 双指针)
排序 + 双指针,时间复杂度 O ( n 2 ) O(n ^ 2) O(n2)
class Solution {
public:
vector<vector<int> > res;
vector<vector<int> > threeSum(vector<int> &num) {
int n = num.size();
sort(num.begin(),num.end());
for(int i = 0;i < n;i ++ )
{
if(i != 0 && num[i] == num[i - 1]) continue;
int l = i + 1,r = n - 1;
while(l < r)
{
int sum = num[i] + num[l] + num[r];
if(sum > 0)
{
r -- ;
continue;
}
else if(sum < 0)
{
l ++;
continue;
}
res.push_back({
num[i] , num[l] , num[r]});
// 去重
do{
l ++ ;}while(l < r && num[l] == num[l -1 ]);
do{
r -- ;}while(l < r && num[r] == num[r + 1]);
}
}
return res;
}
};
最长回文子串(枚举,双指针)
class Solution {
public:
int getLongestPalindrome(string s, int n) {
// write code here
/*
以每个点为中心向两边扩展,回文串为奇数和偶数
*/
int len = 0;
for(int k = 0;k < n; k ++ )
{
// 回文串是奇数
int i = k, j = k;
while(i >= 0 && j < n && s[i] == s[j]) i --, j ++ ;
len = max(len,j - i - 1);
// 回文串是偶数
i = k,j = k + 1;
while(i >= 0 && j < n && s[i] == s[j]) i --, j ++ ;
len = max(len,j - i - 1);
}
return len;
}
};
容器盛水问题(单调栈)
class Solution {
public:
/**
* max water
* @param arr int整型vector the array
* @return long长整型
*/
long long maxWater(vector<int>& arr) {
// write code here
stack<int> stk; // 维护一个单调下降的栈
int n = arr.size();
long long res = 0;
for(int i = 0;i < n;i ++ )
{
while(stk.size() && arr[i] >= arr[stk.top()]) // 单调栈存的是下标
{
int bottom = stk.top();
stk.pop();
if(stk.empty()) break;
int r = i;
int l = stk.top();
res += (long long)(r - l - 1) * (min(arr[r],arr[l]) - arr[bottom]);
}
stk.push(i);
}
return res;
}
};
单链表的排序(归并排序)
前置知识:1. 快慢指针 2. 归并排序 3. 合并两个有序链表
题解
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
ListNode* sortInList(ListNode* head) {
// write code here
if(!head || !head->next) return head;
auto fast = head,slow = head;
while(fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
}
fast = slow;
slow = slow->next; // slow 指向中间节点
fast->next = NULL;
// 归并排序
ListNode *left = sortInList(head);
ListNode *right = sortInList(slow);
return merge_sort(left,right);
}
ListNode* merge_sort(ListNode *l1,ListNode *l2)
{
ListNode *dummy = new ListNode(-1);
auto cur = dummy;
while(l1 && l2)
{
if(l1->val < l2->val)
{
cur->next = l1;
l1 = l1->next;
}
else{
cur->next = l2;
l2 = l2->next;
}
cur = cur->next;
}
cur->next = l1 == NULL ? l2 : l1;
return dummy->next;
}
};
二叉树的镜像(递归)
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
dfs(pRoot);
}
void dfs(TreeNode *root)
{
if(!root) return ;
auto left = root->left,right = root->right;
root->left = right,root->right = left;
dfs(root->left);
dfs(root->right);
}
};