【2023/2/15~2/17 Leetcode】链表练习集锦

1.优先级队列

例题23.合并k个有序队列
变体:【暂未搞懂】
313.超级丑数
378.有序矩阵中第k小的元素
373.查找和最小的K对数字
355.设计推特
tips:

  1. priority_queue:优先级队列
  2. 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;
    }
};

//新解法:
题解2class 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 个一组反转链表
如何判断回文链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值