寻找第K大
// 快排 + 二分搜索
int quickSort(vector<int>& a, int l, int r, int k) {
int i = l, j = r;
int base = a[l];
while(j > i) {
while(j > i && base >= a[j]) j--;
a[i] = a[j];
while(j > i && base <= a[i]) i++;
a[j] = a[i];
}
a[i] = base;
if (i > k - 1)
return quickSort(a, l, i-1, k);
else if (i < k - 1)
return quickSort(a, i+1, r, k);
else
return base;
}
链表倒数第k个
// 返回倒数第k个元素
int kthToLast(ListNode* head, int k) {
ListNode* slow = head;
ListNode* fast = head;
for (int i = 0; i < k - 1; i++) {
fast = fast->next;
}
while(fast->next != NULL) {
slow = slow->next;
fast = fast->next;
}
return slow->val;
}
// 删除倒数第k个元素
ListNode* removeNthFromEnd(ListNode* head, int n) {
// write code here
ListNode* new_root = new ListNode(0);
new_root->next = head;
ListNode* slow = new_root;
ListNode* fast = new_root;
for (int i = 0; i < n; i++) {
fast = fast->next;
}
while(fast->next != NULL) {
slow = slow->next;
fast = fast->next;
}
slow->next = slow->next->next;
// 只有一个元素删除第一个
return new_root->next;
}
链表相加
// 递归实现加法, k是进位
void recur(ListNode* head1, ListNode* head2, ListNode* head, int k) {
if (!head1 && !head2) {
// 最后一位
head->next = (k == 0?NULL:new ListNode(k));
head = head->next;
return ;
}
// 少的部分全部补0
int val1 = head1 == NULL?0:head1->val;
int val2 = head2 == NULL?0:head2->val;
int sum = val1 + val2 + k;
int val = sum % 10;
k = sum / 10;
ListNode* node = new ListNode(val);
head->next = node;
head = head->next;
head1 = head1==NULL?NULL:head1->next;
head2 = head2==NULL?NULL:head2->next;
recur(head1, head2, head, k);
}
ListNode* reverse(ListNode* head) {
ListNode* cur = head, *pre = NULL;
while(cur != NULL) {
ListNode* temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
ListNode* addInList(ListNode* head1, ListNode* head2) {
// write code here
ListNode* root = new ListNode(0);
ListNode* res = root;
recur(reverse(head1), reverse(head2), root, 0);
return reverse(res->next);
}
寻找闭环入口
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
/* 集合插入失败, 就是入口点
set<ListNode*> s;
while(head != NULL) {
auto it = s.insert(head);
if (!it.second)
return head;
head = head->next;
}
return NULL;
*/
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) {
ListNode* another_slow = head;
while(another_slow != slow) {
slow = slow->next;
another_slow = another_slow->next;
}
return slow;
}
}
return NULL;
}
};
每k个结点反转
- 需要三个指针, 一个用来记录开始位置, 两个用来反转
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
void reverse(ListNode* base, ListNode* pre, ListNode* cur, int k) {
ListNode* test = cur;
// 判断最后剩余的不能被反转的
for (int i = 0; i < k - 1; i++){
if (test == NULL) return ;
test = test->next;
}
for (int i = 0; i < k - 1; i++){
ListNode* temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
ListNode* temp = base->next;
base->next = pre;
pre = temp;
pre->next = cur;
// 最后剩余的不能被反转的
if (cur == NULL) return;
reverse(pre, cur, cur->next, k);
}
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
if (head == NULL)
return head;
ListNode* new_root = new ListNode(0);
new_root->next = head;
ListNode* temp = new_root;
reverse(temp, head, head->next, k);
return new_root->next;
}
};
双指针找第一个共同节点
// 只要有共同节点, 总会相遇
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
ListNode* slow = pHead1;
ListNode* fast = pHead2;
while(slow != fast) {
slow = slow==NULL?pHead1:slow->next;
fast = fast==NULL?pHead2:fast->next;
}
return slow;
}
};
// set
class Solution {
public:
ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
set<ListNode*> s;
while(headA != NULL) {
s.insert(headA);
headA = headA->next;
}
while(headB != NULL) {
auto it = s.insert(headB);
if (!it.second)
return headB;
headB = headB->next;
}
return NULL;
}
};
递归法----合并k列表
// 每次对比所有头指针, 最小的头指针后移
void recurMerge(vector<ListNode*>& lists, ListNode* new_head) {
int count = 0;
for (ListNode* head : lists) {
if (head == NULL)
count++;
}
if (count == lists.size())
return;
int min = INT_MAX;
int index = -1;
for (int i = 0; i < lists.size(); i++) {
if (lists[i] != NULL) {
if (lists[i]->val < min) {
min = lists[i]->val;
index = i;
}
}
}
new_head->next = lists[index];
new_head = new_head->next;
lists[index] = lists[index]->next;
recurMerge(lists, new_head);
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* new_root = new ListNode(0);
ListNode* temp = new_root;
recurMerge(lists, temp);
return new_root->next;
}
// 合并k个列表, 就是两两合并
class Solution {
public:
ListNode* recurMerge(ListNode* l1, ListNode* l2) {
ListNode* root = new ListNode(0);
ListNode* temp = root;
while (l1 && l2) {
if (l1->val < l2->val) {
temp->next = l1;
l1 = l1->next;
}
else {
temp->next = l2;
l2 = l2->next;
}
temp = temp->next;
}
temp->next = (l1 == NULL?l2:l1);
return root->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.size() == 0)
return NULL;
ListNode* ans = NULL;
for (int i = 0; i < lists.size(); i++) {
ans = recurMerge(ans, lists[i]);
}
return ans;
}
};
// 分治
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* root = new ListNode(0);
ListNode* temp = root;
while(l1 && l2) {
if (l1->val < l2->val) {
temp->next = l1;
l1 = l1->next;
} else {
temp->next = l2;
l2 = l2->next;
}
temp = temp->next;
}
temp->next = (l1 == NULL?l2:l1);
return root->next;
}
ListNode* merge(vector<ListNode*>& lists, int l, int r) {
if (l == r) return lists[l];
if (l > r) return NULL; //输入[]
int mid = l + (r - l) / 2;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge(lists, 0, lists.size() - 1);
}
- 递归多少次就有多少代价的栈空间
vector中最长无重复子串
class Solution {
public:
/**
*
* @param arr int整型vector the array
* @return int整型
*/
/*
*
* 一左一右双指针, 一起从头出发, 结果初始化为1, r不到最后一个元素, r++, 判断下一个元素在不在前面的子串中, 在的话, 移动l, 不在的话, 更新结果
* find函数找不到元素的话, 迭代器返回的是第二个参数
*/
int maxLength(vector<int>& arr) {
// write code here
auto l = arr.begin();
auto r = arr.begin();
int res = 1;
// 不等于最后一个元素的迭代器, 迭代器是可以+-, 但不能比大小
while(r != arr.end()-1) {
r++;
auto it = find(l, r, *r);
if (it != r) {
// 每次都是在上一次的l开始增加
l = l + distance(l, it) + 1;
} else {
// distance不是int类型
res = max(res, int(distance(l, r)) + 1);
}
}
return res;
}
};
最长有效括号子串
class Solution {
public:
/**
*
* @param s string字符串
* @return int整型
*/
int longestValidParentheses(string s) {
// write code here
int n = s.size();
int res = 0;
// dp[i]表示以i结尾的最长有效子串, 所以要找dp中最大的一个. 如果没有结尾, 就是dp[n-1]
vector<int> dp(n, 0);
for (int i = 0; i < n; i++) {
if (s[i] == ')') {
if (s[i-1] == '(')
dp[i] = (i-2>=0?dp[i-2]:0) + 2;
else if (i - dp[i-1] > 0 && s[i - dp[i-1] -1] =='(')
dp[i] = dp[i - 1] + 2 + (i-dp[i-1]>=2?dp[i - dp[i - 1] - 2]:0);
res = max(res, dp[i]);
}
}
return res;
}
};
三元组为定值
/**
* (1)首先对数组进行排序(从小到大)
* (2)依次取出第 i 个数(i从0开始),并且不重复的选取(跳过重复的数)
* (3)这样问题就转换为 2 个数求和的问题(可以用双指针解决方法)
* 2 数求和问题
* (4)定义两个指针:左指针(left) 和 右指针(right)
* (5)指向排序数组的一头一尾, 两个数的和为定值, 其中一个增大另一个比减少.
* (6)根据和结果的对比, 进行left++, right--相关操作
* (7)时间复杂度:O(nlogn) + O(n)
*/
class Solution {
public:
vector<vector<int> > threeSum(vector<int> &num) {
vector<vector<int>> res;
int n = num.size();
// 方便之后操作
sort(num.begin(), num.end());
for (int i = 0; i < n; i++) {
// 因为和是0, 并且num[i]是最小的一个
if (num[i] > 0)
break;
// 去掉重复的结果
if (i >= 1 && num[i] == num[i-1])
continue;
int temp = -num[i];
// 两个数字相加为定值, 其中一个增大, 另一个只能减少, 才有可能还等于这个定植
int l = i + 1, r = num.size() - 1;
while(l < r) {
if (num[r] + num[l] == temp) {
// vector底层就是数组, 以后就不用再创建一个临时vector了
res.push_back({num[i], num[l], num[r]});
// 去掉重复的结果
while(l < r && num[l] == num[l+1]) l++;
while(l < r && num[r] == num[r-1]) r--;
l++;r--;
}
else if (num[r] + num[l] > temp) r--;
else if (num[r] + num[l] < temp) l++;
}
}
return res;
}
};