1.优先级队列
例题:23.合并k个有序队列
变体:【暂未搞懂】
313.超级丑数
378.有序矩阵中第k小的元素
373.查找和最小的K对数字
355.设计推特
tips:
- priority_queue:优先级队列
- for(auto a:b)中b为一个容器,效果是利用a遍历并获得b容器中的每一个值,但是a无法影响到b容器中的元素。
for(auto &a:b)中加了引用符号,可以对容器中的内容进行赋值,即可通过对a赋值来做到容器b的内容填充。
分治解法
class Solution {
public:
ListNode* mergetwoLists(ListNode *a,ListNode *b){
if ((!a) || (!b)) return a ? a : b;
ListNode *dummy=new ListNode(-1);
ListNode *p1=a,*p2=b;
ListNode *p=dummy;
while(p1!=nullptr && p2 !=nullptr){
if(p1->val<p2->val){
p->next=p1;
p1=p1->next;
}
else{
p->next=p2;
p2=p2->next;
}
p=p->next;
}
if(p1!=nullptr) p->next=p1;
if(p2!=nullptr) p->next=p2;
return dummy->next;
}
ListNode* merge(vector<ListNode*> &lists,int l,int r){
if(l==r) return lists[l];//此处返回l 不是1....所以超出时间限制
if(l>r) return nullptr;
int mid=(l+r)/2;
return mergetwoLists(merge(lists,l,mid),merge(lists,mid+1,r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge(lists,0,lists.size()-1);
}
};
2.如果链表中含有环,如何计算这个环的起点
解法:相遇后,把快慢指针中的任一个重新指向 head,然后两个指针同速前进,k - m 步后一定会相遇,相遇之处就是环的起点了。(有点不理解)
ListNode detectCycle(ListNode head) {
ListNode fast, slow;
fast = slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) break;
}
// 上面的代码类似 hasCycle 函数
if (fast == null || fast.next == null) {
// fast 遇到空指针说明没有环
return null;
}
// 重新指向头结点
slow = head;
// 快慢指针同步前进,相交点就是环起点
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
3.两个链表是否相交
题目来源:相交链表
解法:
//通过用例27/39 解法
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1=headA;
ListNode *p2=headB;
while(p1!=p2)
{
if(p1==NULL&&p2==NULL)
return NULL;
else if(p1==NULL)
p1=headB;
else if(p2==NULL)
p2=headA;
p1=p1->next;
p2=p2->next;
}
return p1;
}
};
//满分解法
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *p1=headA;
ListNode *p2=headB;
while(p1!=p2)
{
if(p1==NULL)
p1=headB;
else
p1=p1->next;
if(p2==NULL)
p2=headA;
else
p2=p2->next;
}
return p1;
}
};
//其它思路解法
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = 0, lenB = 0;
// 计算两条链表的长度
for (ListNode p1 = headA; p1 != null; p1 = p1.next) {
lenA++;
}
for (ListNode p2 = headB; p2 != null; p2 = p2.next) {
lenB++;
}
// 让 p1 和 p2 到达尾部的距离相同
ListNode p1 = headA, p2 = headB;
if (lenA > lenB) {
for (int i = 0; i < lenA - lenB; i++) {
p1 = p1.next;
}
} else {
for (int i = 0; i < lenB - lenA; i++) {
p2 = p2.next;
}
}
// 看两个指针是否会相同,p1 == p2 时有两种情况:
// 1、要么是两条链表不相交,他俩同时走到尾部空指针
// 2、要么是两条链表相交,他俩走到两条链表的相交点
while (p1 != p2) {
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
4. 删除排序链表中的重复元素
题目来源:力扣82题
题解:
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode *dummy=new ListNode(-1);
dummy->next=head;
ListNode *p=dummy;
int x;
while(p->next&&p->next->next){
x=p->next->val;
if(p->next->next->val!=x){
p=p->next;
}
else{
while(p->next&&p->next->val==x){//注意这里也要判断p->next,不然执行错误。
p->next=p->next->next;
}
}
}
return dummy->next;
}
};
5. 有序链表转换二叉搜索树(重要)(分治法)
题目来源:有序链表转换二叉搜索树
解法:
class Solution {
public:
ListNode* getmid(ListNode* a,ListNode* b){
ListNode *fast=a;
ListNode *slow=a;
while(fast!=b&&fast->next!=b){
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
TreeNode* buildtree(ListNode* a,ListNode* b){
if(a==b)
return nullptr;
ListNode *mid=getmid(a,b);
TreeNode *root=new TreeNode(mid->val);
root->left=buildtree(a,mid);
root->right=buildtree(mid->next,b);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
return buildtree(head,nullptr);
}
};
6. 回文链表
题目来源:回文链表
题解:
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> vals;
while (head != nullptr) {
vals.emplace_back(head->val);
head = head->next;
}
for (int i = 0, j = (int)vals.size() - 1; i < j; ++i, --j) {
if (vals[i] != vals[j]) {
return false;
}
}
return true;
}
};
//自己写的
class Solution {
public:
bool isPalindrome(ListNode* head) {
int vals[100001];//注意数组越界
int i=0;
while(head!=nullptr){
vals[i++]=head->val;
head=head->next;
}
i--;
for(int j=0;j<i;j++,i--)
{
if(vals[j]!=vals[i]){
//cout<<"j="<<j<<" i="<<i<<" "<<vals[j]<<" -- "<<vals[i]<<endl;
return false;
}
}
return true;
}
};
//新解法:
题解2:
class Solution {
public:
ListNode* rever(ListNode* head){
ListNode *pre = nullptr, *cur = head;
while (cur != nullptr) {
ListNode *next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
bool isPalindrome(ListNode* head) {
ListNode *slow,*fast;
slow=fast=head;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
}
if(fast!=nullptr)
slow=slow->next;
ListNode *left=head;
ListNode *right=rever(slow);
while(right!=nullptr){
if(left->val!=right->val)
return false;
left=left->next;
right=right->next;
}
return true;
}
};
7. 动态规划
题目来源:交错字符串
题解:
class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
auto f = vector < vector <int> > (s1.size() + 1, vector <int> (s2.size() + 1, false));
int n = s1.size(), m = s2.size(), t = s3.size();
if (n + m != t) {
return false;
}
f[0][0] = true;
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
int p = i + j - 1;
if (i > 0) {
f[i][j] |= (f[i - 1][j] && s1[i - 1] == s3[p]);
}
if (j > 0) {
f[i][j] |= (f[i][j - 1] && s2[j - 1] == s3[p]);
}
}
}
return f[n][m];
}
};
#滚动数组优化
剑指offer46.把数字翻译成字符串
70.爬楼梯
63.不同路径Ⅱ
学习参考:
双指针技巧秒杀七道链表题目
递归魔法:反转单链表
如何 K 个一组反转链表
如何判断回文链表