【数据结构】链表常见题目-ToDone

news2024/11/17 13:42:58

文章目录

    • 合并两个有序链表
    • 反转链表
    • 链表内指定区间反转
    • 复制带随机指针的链表
    • 环形链表
    • 环形链表II
    • 相交链表
    • 移除链表元素
    • 链表中倒数第k个节点
    • 链表分割
    • 链表的回文结构
    • 链表的中间节点
    • 旋转链表
    • 链表排序
    • 链表求和 (逆序求)
    • 链表求和II (正序求)
    • 重排链表
    • 链表的奇偶重排
    • 奇偶链表
    • 反转链表II
    • 删除链表中的节点
    • 删除有序链表当中重复的元素I
    • 删除有序链表当中重复的元素II
    • 合并K个升序链表
    • K个一组反转链表
    • 交换链表中的节点
    • 二进制链表转整数
    • 链表随机节点

合并两个有序链表

https://leetcode.cn/problems/merge-two-sorted-lists/

1.定义一个哨兵位节点和一个tail节点标志尾节点

2.遍历两条有序链表,谁小就链接谁

3.最后还剩一条链表是没有遍历完成的,那么就让tail节点链接它

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        //1.新建哨兵位节点
        ListNode* phead = new ListNode(-1);
        ListNode* tail = phead;
        //2.谁小就链接谁
        while(list1 && list2)
        {
            if(list1->val > list2->val)
            {
                tail->next = list2;
                tail = list2;
                list2 = list2->next;
            }
            else 
            {
                tail->next = list1;
                tail = list1;
                list1 = list1->next;
            }
        }
        //3.判断谁还没有链接完
        if(list1) tail->next = list1;
        if(list2) tail->next = list2;

        return phead->next;
    }
};

反转链表

https://leetcode.cn/problems/reverse-linked-list/description/

prev:记录前一个节点 cur:当前遍历到的节点 next:保存cur的下一个节点

  • 先保存下一个节点 然后更改cur的指向,指向前一个节点
  • 然后迭代往后走
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* prev = nullptr;//记录前一个节点
        ListNode* cur = head;//记录当前节点
        ListNode* next = nullptr;//记录下一个节点
        while(cur)
        {
            next = cur->next;//先保存下一个节点
            cur->next = prev;//更改当前节点指向
            //prev cur next 迭代往后走
            prev = cur;
            cur = next;
        }
        return prev;
    }
};

链表内指定区间反转

https://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c?tpId=295&tqId=654&ru=%2Fpractice%2F6ab1d9a29e88450685099d45c9e31e46&qru=%2Fta%2Fformat-top101%2Fquestion-ranking&sourceUrl=%2Fexam%2Fcompany

复制带随机指针的链表

https://leetcode.cn/problems/copy-list-with-random-pointer/

1.在原链表节点之后拷贝一个节点

image-20230816094513759

2.处理拷贝节点的random指针

  • 注意:拷贝节点的random指针指向的节点是其原链表节点的random指针指向的节点的下一个节点
  • 坑点:有可能cur->random是空,也就是原来节点的random指针为空,那么当前拷贝节点的random指针也应该为空,否则cur->random->next 就会对空指针解引用!

image-20230816094637865

3.分离两条链表

  • 最好定义一个哨兵位节点和一个tail指针用于标记链接拷贝链表,
  • cur CopyCur next三者的关系重新处理

image-20230816094751726

class Solution {
    public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr ) return nullptr;
        //1.在原节点后面copy一个节点
        Node* cur = head;
        while(cur)
        {
            Node* copy = new Node(cur->val);//拷贝节点
            Node* next = cur->next;
            //cur copy next 链接
            cur->next = copy;
            copy->next = next;

            cur = next;//继续复制下一个节点
        }
        //2.处理拷贝节点的random指针
        cur = head;
        while(cur)
        {
            Node* curCopy = cur->next;//cur的拷贝节点
            curCopy->random = cur->random == nullptr?nullptr:cur->random->next;
            cur = curCopy->next;
        }
        //3.拆离拷贝链表
        cur = head;
        Node* pnewHead = new Node(-1);//哨兵位
        Node* tail = pnewHead;
        while(cur)
        {
            //cur copyCur next  
            Node* copyCur = cur->next;
            Node* next = copyCur->next;
			
            copyCur->next = nullptr;//让拷贝节点独立存在
            tail->next = copyCur;
            tail = tail->next;
			//重新处理链接关系,向后走
            cur->next = next;
            cur = next;
        }
        return pnewHead->next;
    }
};

环形链表

https://leetcode.cn/problems/linked-list-cycle/description/

方法:使用快慢指针,二者从头开始走,一个一次走两步,一个一次走一步,当二者相遇的时候,说明有环

class Solution {
public:
    bool hasCycle(ListNode *head) {
        //链表为空
        //注意:一个节点也能成环! 自己指向自己
        if(!head) return false;

        //快慢指针
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            //二者相遇  注意:该条件不能放在上面!!!因为最初fast和slow都指向head,该条件应该放在下面
            if(slow == fast) 
                return true;
        }
        return false;
    }
};

延申1:fast一次走两步,slow一次走一步,为什么一定能相遇?会不会在环里错过,永远遇不上

结论:slow一次走一步,fast一次走两步,如果存在环,slow和fast一定会在环内相遇

1.slow和fast,如果有环,一定是fast先进环,这时slow走了入环前距离的一半

2.随着slow进环,fast已经在环里面走了一段距离了(距离的多少跟环的大小有关)

  • 假设slow进环的时候,slow和fast的距离为N,fast开始追赶slow

3.slow一次走一步,fast一次走两步,二者的距离变化为:N N- 1 N -2 … 0,当二者的距离变为0的时候,就是相遇了

延申2:fast一次走n步(n>2),slow一次走一步,fast和slow能相遇吗

结论:fast一次走n步(n>2),slow一次走一步,不一定会相遇

  • 假设有环,fast一次走n步,slow一次走1步,fast和slow的距离不断减少n-1步

例子:假设fast一次走3步,如果slow进环之后,slow和fast的距离为N

如果N为偶数,那么二者之间的距离变化为:N N - 2 N - 4 … 2 0,此时二者相遇

如果N为计数,那么二者之间的距离变化为:N N - 2 N - 4 … 1 -1 ,二者距离变为-1,意味着fast超越了slow,此时fast和slow的距离为C -1 (假设C为环的大小)

  • 如果C - 1 为偶数,那么下一轮fast可以追上slow,二者相遇
  • 如果C - 1 为奇数,那么二者永远追不上

环形链表II

https://leetcode.cn/problems/linked-list-cycle-ii/description/

做法:

1.先看是否有环,快慢指针,fast一次走两步,slow一次走一步,如果存在环,fast和slow一定会相遇

2.假设相遇点为meetnode,一个指针从链表的头开始走,一个指针从相遇点开始走,二者一次走一步,当二者相遇的时候,该位置就是入环节点

image-20230816102819793

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(!head) return nullptr;
        //快慢指针
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
            //二者相遇  注意:该条件不能放在上面!!!因为最初fast和slow都指向head,该条件应该放在下面
            if(slow == fast) 
            {
                //分别从相遇点和链表头开始走,一次走一步  此时相遇就是入环位置
                ListNode* meet = slow;
                slow = head;
                while(slow != meet) 
                {
                    slow = slow->next;
                    meet = meet->next;
                }
                return meet;
            }
        }
        return nullptr; //没有环
    }
};

相交链表

https://leetcode.cn/problems/intersection-of-two-linked-lists/description/

方法1:将A链表的所有节点放到容器当中(要放地址,不能放值),然后遍历B链表,看能否在容器当中找到该元素,如果找到,那么该节点就是相交节点

class Solution {
public:
    //方法1:用容器保存其中一个链表的节点,然后遍历另外一个链表进行比对
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        multiset<ListNode*> s;
        ListNode* cur = headA;
        while(cur) 
        {
            s.insert(cur);
            cur = cur->next;
        }
        cur = headB;
        while(cur)
        {
            cout << cur->val << endl;
            if(s.find(cur) != s.end()) 
                return cur;
            cur = cur->next;
        }
        return nullptr;//不相交
    }
};

方法2:A中的每个结点和B分别比较(B和A比较也可以),看二者的地址是否一致 - O(N*M)

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode* curA = headA;
        ListNode* curB = headB;
        while(curA) //确定一个A节点
        {
            curB = headB;
            while(curB)//遍历整条B链表
            {
                if(curA == curB)
                {
                    return curA;
                }
                curB = curB ->next;
            }
            curA = curA->next;
        }
        return nullptr;
    }
};

方法3:

1.先统计两条链表的长度,假设二者长度差距为gap

2.长链表先往后走gap步,然后长短链表一起往后走,如果相遇,那么就是相交节点

class Solution {
    public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(!headA || !headB) return nullptr;
        //1.统计两条链表的长度
        int lenA = 0;
        int lenB = 0;
        ListNode* cur = headA;
        while(cur)  lenA++,cur = cur->next;
        cur = headB;
        while(cur) lenB++,cur = cur->next;

        //2.看哪条链表更长
        ListNode* LongList = headA;
        ListNode* shortList = headB;
        if(lenA < lenB)  //B链表更长
            swap(LongList,shortList); 

        //3.长链表先走|lenA - lenB|步
        int gap = abs(lenA - lenB);
        while(gap--)
        {
            LongList = LongList -> next;
        }
        //4.二者一起走,相遇就是相交节点
        while(LongList != shortList)
        {
            LongList = LongList->next;
            shortList = shortList->next;
        }
        return LongList;
    }
};

移除链表元素

https://leetcode.cn/problems/remove-linked-list-elements/description/

1.遍历链表,先保存下一个节点,然后将当前节点独立,判断当前节点的值是否是要删除的值

2.如果是,那么就要将当前节点是否,否则将其链接到哨兵位链表

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        if(!head) return nullptr;
        ListNode* phead = new ListNode(-1);//哨兵位
        ListNode* tail = phead;
        ListNode* cur = head;
        while(cur)
        {
            ListNode* next = cur ->next;//保存下一节点
            //将当前节点独立!!否则其next还是指向原来的链表的内容
            cur->next = nullptr;
            if(cur->val != val)
            {
                tail->next = cur;
                tail = tail->next;
            }
            else  //当前节点要释放
            {
                delete cur;
            }
            cur = next;
        }
        return phead->next;
    }
};

链表中倒数第k个节点

https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

做法:快慢指针,快指针先走k步,然后快慢指针一起走,最后慢指针指向的就是倒数第k个节点

  • while(k--):执行k次 while(--k):执行k-1次

坑点:有可能k是超过链表长度,那么有可能快指针提前走到空!

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
		ListNode* fast = pListHead;
		ListNode* slow = pListHead;
		while(k--) //快指针先走k步
		{
			if(fast == nullptr)  //k超过了链表长度了
				return nullptr;
			fast = fast->next;
		}
		//快慢指针一起走,当fast为空,此时slow就是倒数第k个节点
		while(fast)
		{
			fast = fast->next;
			slow = slow->next;
		}
		return slow;
    }
};

链表分割

https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

1.使用两条链表,一条链表记录大于x的节点,一条链表记录小于x的节点。因为不能改变原来的数据顺序,所以要采取尾插,而不是头插

2.遍历原链表,首先记录下一个节点,把当前节点独立,如果当前节点的值<x,那么把当前节点尾插到记录小于x的节点的链表,否则将当前节点尾插到记录大于x的节点的链表

3.最后两条链表进行链接,注意:有可能所有节点的值>x,那么记录<x的节点的链表就是空

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        ListNode* BigThanXHead = nullptr,*BigThanXTail = nullptr;
        ListNode* LessThanXHead = nullptr,*LessThanXTail = nullptr;
        ListNode* cur = pHead;
        while(cur)
        {
            //最好将当前节点单独摘下来!!!否则其next还是指向原来的内容
            ListNode* next = cur->next;
            cur->next = nullptr;
            if(cur->val < x)
            {
                if(LessThanXHead == nullptr)
                {
                    LessThanXTail = LessThanXHead = cur;
                }
                else 
                {
                    LessThanXTail->next = cur;
                    LessThanXTail = LessThanXTail->next;
                }
            }
            else 
            {
                if(BigThanXHead == nullptr)
                {
                    BigThanXTail = BigThanXHead = cur;
                }
                else 
                {
                    BigThanXTail->next = cur;
                    BigThanXTail = BigThanXTail->next;
                }
            }
            cur = next;
        }
        //两段链表进行链接
        if(LessThanXHead != nullptr)
        {
            LessThanXTail->next = BigThanXHead;
        }
        return LessThanXHead != nullptr?LessThanXHead :BigThanXHead;
    }
};

链表的回文结构

https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking

方法1:将所有节点的值放到栈中,然后再次遍历链表判断值是否和栈顶节点一致

class PalindromeList {
    public:
    bool chkPalindrome(ListNode* A) {
        stack<int> st;
        ListNode* cur = A;
        while(cur)
        {
            st.push(cur->val);
            cur = cur->next;
        }
        cur = A;
        while(cur)
        {
            if(cur->val != st.top())
                return false;
            cur = cur->next;
            st.pop();
        }
        return true;
    }
};

方法2:链表反转 + 返回链表的中点

1.找到链表的中间节点midNodePrev,以head为头作为第一条链表,以midNodePrev->next为头作为第二条链表,然后将将midNodePrev的next指针置为空

2.反转第二条链表,然后两条链表遍历比较,如果值不想同,那么说明不回文

class PalindromeList {
  public: 
    ListNode* reverseList(ListNode* head) { //链表反转
        ListNode* prev = nullptr;//记录前一个节点
        ListNode* cur = head;//记录当前节点
        ListNode* next = nullptr;//记录下一个节点
        while (cur) {
            next = cur->next;//先保存下一个节点
            cur->next = prev;//更改当前节点指向
            //prev cur next 迭代往后走
            prev = cur;
            cur = next;
        }
        return prev;
    }
    //返回中点
    ListNode* middleNode(ListNode* head) {
        if (!head) return nullptr;
        //快慢指针-快指针走两步,慢指针走一步,当快指针结束时,慢指针指向的就是中间节点
        ListNode* fast = head, *slow = head;
        while (fast && fast->next) {
            fast = fast->next->next;
            slow = slow->next;     
        }
        return slow;
    }
    bool chkPalindrome(ListNode* A) {
        if(A == nullptr ) return false;
        if(A->next == nullptr) return true;
        ListNode* midNodePrev = middleNode(A);
        ListNode* secondList = midNodePrev->next;
        ListNode* firstList = A;
        midNodePrev->next = nullptr;//分离两条链表

        secondList = reverseList(secondList);

        ListNode* curA = firstList,*curB = secondList;
        while(curA && curB)
        {
            if(curA->val != curB->val) return false;
            curA = curA->next;
            curB = curB->next;
        }
        return true;
    }
};

链表的中间节点

https://leetcode.cn/problems/middle-of-the-linked-list/description/)/

快慢指针:快指针走两步,慢指针走一步,当快指针结束时,慢指针指向的就是中间节点

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        if(!head) return nullptr;
        //快慢指针-快指针走两步,慢指针走一步,当快指针结束时,慢指针指向的就是中间节点
        ListNode* fast = head,*slow = head;
        while(fast && fast->next)
        {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }
};

旋转链表

https://leetcode.cn/problems/rotate-list/

链表排序

https://leetcode.cn/problems/sort-list/

两个子函数:找链表的中间节点的上一个 + 合并两条有序链表

做法:

  • 1.如果链表为空 || 链表只有一个节点 那么直接返回
  • 2.找链表的中间节点的上一个节点记为:mid,然后保存mid的下一个节点记为midNext,然后将mid->next置为空
  • 3.分别排序:以head为头的链表,以midNext为头的链表,然后两条链表进行归并
    • $[head,mid] $ $ [mid->next,…]$
class Solution {
    public:
    //分割两段链表 ==>找链表的中间节点的上一个
    ListNode* splitList(ListNode* head)
    {
        if(!head || !head->next)     return head;
        ListNode* fast = head;
        ListNode* slow = head;
        ListNode* prev = head;
        while(fast&&fast->next)
        {
            prev = slow;
            fast = fast->next->next;
            slow = slow->next;
        }
        return prev;
    }
    //合并两条有序链表
    ListNode* MergeSort(ListNode* head1,ListNode* head2)
    {
        ListNode* dummy = new ListNode(-1);
        ListNode* tail = dummy;
        while(head1 && head2)
        {
            if(head1->val < head2->val)
            {
                tail->next = head1;
                tail = head1;
                head1 = head1->next;
            }
            else
            {
                tail->next = head2;
                tail = head2;
                head2 = head2->next;
            }
        }
        if(head1)   tail->next = head1;
        if(head2)   tail->next = head2;

        return dummy->next;
    }
    ListNode* sortList(ListNode* head) {
        if(!head || !head->next)    return head;
        ListNode* mid = splitList(head);
        ListNode* midNext = mid->next;
        mid->next = nullptr;
        //[head,mid] [mid->next,....]
        ListNode* head1 = sortList(head);
        ListNode* head2 = sortList(midNext);
        return MergeSort(head1,head2);
    }
};

问题:为什么是返回链表中点的上一个

因为如果是直接返回链表中点,假设链表现在为 4 − > 2 4->2 4>2

  • 那么此时mid就是2节点,然后midNext为空,然后又去递归sortList( h e a d : 4 − > 2 head:4->2 head:4>2),得到的mid又是2,然后又去递归… 就会造成死循环
  • 而如果返回的是链表的中点的上一个就不会有问题!

链表求和 (逆序求)

https://leetcode.cn/problems/sum-lists-lcci/

image-20230816171553721

做法:定义一条临时链表维护计算结果

1.如果其中一条链表尾空,那么就返回另外一条链表

2.如果其中一条链表没有遍历完 || 进位不为0,都继续操作

  • 当前计算节点相加的值,注意不要忽略进位!用当前计算值开辟一个节点然后计算向下一位的进位
class Solution {
    public:
    ListNode* addTwoNumbers(ListNode* list1, ListNode* list2) {
        if(!list1 && !list2) return nullptr;
        //如果其中一条链表尾空,那么就返回另外一条链表
        if(!list1) return list2;
        if(!list2) return list1; 

        ListNode* phead  = new ListNode(-1);
        ListNode* tail = phead;

        int carry = 0;//进位
        while(list1|| list2 || carry) //其中一条链表没有遍历完 || 进位不为0,都继续操作
        {
            int sum = 0;//当前计算节点相加的值,注意:每次都需要重新将sum置为0!!否则还是上次计算的值
            if(list1 != nullptr)
            {
                sum += list1->val,list1 = list1->next;
            }
            if(list2 != nullptr) 
            {
                sum += list2->val,list2 = list2->next;
            }

            sum += carry;//注意要加上进位值
            carry = sum / 10; //坑点:carry的计算要放在sum取模之前,否则每次carry的值都是0
            sum = sum % 10;

            ListNode* newNode = new ListNode(sum);
            tail -> next = newNode;
            tail = tail->next;
        }
        return phead->next;
    }
};

链表求和II (正序求)

https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId=295&tqId=1008772&ru=/exam/company&qru=/ta/format-top101/question-ranking&sourceUrl=%2Fexam%2Fcompany

image-20230816173539557

class Solution {
public:
    ListNode* ReverseList(ListNode* head) //返回逆置之后的链表的头
    {
        ListNode* cur = head,*prev = nullptr,*next = nullptr;
        while(cur)
        {
            //prev cur next
            next = cur->next;
            cur->next = prev;
            //迭代往后走
            prev = cur;
            cur = next;
        }
        return prev;
    }
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        if(!head1 && !head2) return nullptr;
        //如果其中一条链表为空,那么返回另外一条链表
        if(!head1) return head2;
        if(!head2) return head1;

        //逆置两条链表
        head1 = ReverseList(head1);
        head2 = ReverseList(head2);
        //正序求和
        ListNode* phead = new ListNode(-1);
        ListNode* tail = phead;
        int carry = 0;
        while(head1 || head2 || carry)
        {
            int sum = 0;
            if(head1) sum += head1->val,head1 = head1->next;
            if(head2) sum += head2->val,head2 = head2->next;
            sum += carry;

            carry = sum / 10;
            sum = sum % 10;
            tail->next = new ListNode(sum);
            tail = tail->next;
        }
        //逆置结果链表
        return ReverseList(phead->next);
    }
};

重排链表

https://leetcode.cn/problems/reorder-list/

链表的奇偶重排

https://www.nowcoder.com/practice/02bf49ea45cd486daa031614f9bd6fc3?tpId=295&tqId=1073463&ru=%2Fpractice%2Fc087914fae584da886a0091e877f2c79&qru=%2Fta%2Fformat-top101%2Fquestion-ranking&sourceUrl=%2Fexam%2Fcompany

奇偶链表

https://leetcode.cn/problems/odd-even-linked-list/

做法:

反转链表II

https://leetcode.cn/problems/reverse-linked-list-ii/

删除链表中的节点

https://leetcode.cn/problems/delete-node-in-a-linked-list/description/

image-20230816111124672

做法:假设要删除的节点为node,其下一个节点为nodeNext

  • 1.将node节点的值变为nodeNext节点的值,然后让node->next链接nodeNext->next
  • 2.然后删除nodeNext节点

思想:把nodeNext的数据搬到node,然后释放nodeNext节点,让node链接其下一个节点

注意:如果node是尾节点,那么就直接返回,不能处理

class Solution {
public:
    void deleteNode(ListNode* node) {
        //链表为空 || 尾节点
        if(!node  || !node->next) return ;
        ListNode* nodeNext = node->next;
        node->val = nodeNext->val;
        node->next = nodeNext->next;
        delete nodeNext;
    }
};

删除有序链表当中重复的元素I

https://www.nowcoder.com/practice/c087914fae584da886a0091e877f2c79?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Fcompany

删除有序链表当中重复的元素II

https://www.nowcoder.com/practice/71cef9f8b5564579bf7ed93fbe0b2024?tpId=295&tqId=663&ru=%2Fpractice%2Fc56f6c70fb3f4849bc56e33ff2a50b6b&qru=%2Fta%2Fformat-top101%2Fquestion-ranking&sourceUrl=%2Fexam%2Fcompany


合并K个升序链表

https://leetcode.cn/problems/merge-k-sorted-lists/

1.使用一个小根堆进行操作,因为默认是大根堆,所以我们要自定义比较方式!

2.首先先把lists当中所有非空的节点放到堆中,定义一条临时链表用于链接从堆中弹出的节点

3.如果堆不为空就一直处理:弹出当前堆顶节点,如果当前堆顶节点的下一个节点不为空就发给到堆中,将当前节点独立,将当前节点链表到临时链表当中

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto lambda = [](ListNode* l,ListNode* r){ return l->val > r->val;};
        priority_queue<ListNode*,vector<ListNode*>,decltype(lambda)> pq; //默认是大根堆,我们要的是小根堆(排升序)
        for(auto& head : lists)
        {
            if(head != nullptr) pq.push(head);
        }
        ListNode* phead = new ListNode(-1);
        ListNode* tail = phead;
        while(!pq.empty())
        {
            ListNode* top = pq.top();
            pq.pop();

            if(top->next) 
                pq.push(top->next);

            //将当前节点独立
            top->next = nullptr;
            tail->next = top;
            tail = tail->next;
        }
        return phead->next;
    }
};

K个一组反转链表

https://leetcode.cn/problems/reverse-nodes-in-k-group/

交换链表中的节点

https://leetcode.cn/problems/swapping-nodes-in-a-linked-list/description/

二进制链表转整数

https://leetcode.cn/problems/convert-binary-number-in-a-linked-list-to-integer/description/

链表随机节点

https://leetcode.cn/problems/linked-list-random-node/solutions/1210211/lian-biao-sui-ji-jie-dian-by-leetcode-so-x6it/

image-20230816105652221

做法:可以在初始化时,用一个数组记录链表中的所有元素,这样随机选择链表的一个节点,就变成在数组中随机选择一个元素

class Solution {
public:
    vector<int> arr;
    Solution(ListNode* head) {
        while(head)
            arr.push_back(head->val),head = head->next;
    }
    
    int getRandom() {
        return arr[rand() % arr.size()];
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/887097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

V2X——行动胜于概念

摘要&#xff1a; 本文从信号灯服务入手&#xff0c;简单介绍了车路协同工程化落地过程中的一些关键问题和解决方案&#xff0c;包括设备接入、V2X消息层编解码、C-V2X通信&#xff0c;车端消费以及车路协同安全防护等&#xff0c;类似的问题还有很多&#xff0c;需要从业者做…

打开vim的语法高亮

在一个Ubuntu中自带的vim版本是8.2.4919&#xff0c;默认就是开始了语法高亮的&#xff0c;打开一个Java文件效果如下&#xff1a; 它不仅仅对Java文件有语法高亮&#xff0c;对很多的文件都有&#xff0c;比如vim的配置文件也有语法高亮&#xff0c;有语法高亮时读起来会容易…

re学习(33)攻防世界-secret-galaxy-300(动态调试)

下载压缩包&#xff1a; 下载链接&#xff1a;https://adworld.xctf.org.cn/challenges/list 参考文章&#xff1a;攻防世界逆向高手题之secret-galaxy-300_沐一 林的博客-CSDN博客 发现这只是三个同一类型文件的三个不同版本而已&#xff0c;一个windows32位exe&#xff0…

Webpack node、output.jsonpFunction 配置详解

Webpack node、output.jsonpFunction 配置详解 最近尝试给一些用到 webpack 的项目升级到最新 webpack5 版本&#xff0c;其中遇到了一些问题&#xff0c;我挑了两个比较典型的问题&#xff0c;其中主要涉及到了 webpack 的 node 属性跟 output.jsonpFunction &#xff08;web…

opencv图像轮廓检测

效果展示&#xff1a; 代码部分&#xff1a; import cv2 import numpy as np img cv2.imread(C:/Users/ibe/Desktop/picture.PNG,cv2.IMREAD_UNCHANGED) # 类型转换 img cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 结构元 kernel cv2.getStructuringElement(cv2.MORPH_REC…

【网络架构】华为hw交换机网络高可用网络架构拓扑图以及配置

一、网络拓扑 1.网络架构 核心层:接入网络----路由器 汇聚层:vlan间通信 创建vlan ---什么是vlan:虚拟局域网,在大型平面网络中,为了实现广播控制引入了vlan,可以根据功能或者部门等创建vlan,再把相关的端口加入到vlan.为了实现不用交换机上的相同vlan通信,需要配置中继,为了…

考公-判断推理-逻辑判断-削弱类

否定论点&#xff0c;根本排除 例题 例题 例题 例题 例题 例题 变化小&#xff0c;胖了瘦了 例题 例题 拆桥 例题 例题 例题 例题 例题 例题 例题 例题 例题 A类比非常弱 D削弱了论据 例题 因果倒置例题 例题 例题

css学习2(利用id与class修改元素)

1、id选择器可以为标有特定id的html元素指定特定的样式。 2、选择器以#开头&#xff0c;后跟某id的属性值。 3、class选择器用于描述一组元素的样式&#xff0c;class可以在多个元素使用。 4、类选择器用.选择。 5、指定特定的元素使用class。 6、元素的多个类用空格分开&…

python测试 unittest 实践要点

目录 命名篇 命令行篇 测试断言篇 常见测试断言 特殊测试断言 测试前后篇 在每个测试方法前后执行 在每个测试类的所有方法前后执行 不运行测试篇 参考 命名篇 测试模块应以 test_开头 测试类应以Test开头或结尾 测试类中的测试方法应该以test_开头 命令行篇 测…

第二章 Linux系统-系统接口管理

第二章 Linux系统-系统接口管理 ​ 操作系统接口时架构在硬件上的第一层软件&#xff0c;时计算机底层硬件和用户之间的接口&#xff0c;利用操作系统才能使用应用程序&#xff08;或用户&#xff09;对系统硬件的访问。任何操作系统都会想上层提供接口&#xff0c;操作系统接…

应用层自定义协议(组织数据的格式)

概念 在进行网络传输数据的时候&#xff0c;通常是将要传输的数据组织成一个字符串&#xff0c;再将字符串转换为一个字节流进行网络传输数据&#xff0c;而数据组织的格式是多种多样的&#xff0c;我们只需要保证&#xff0c;客户端和服务器对于字符串的组织和解析统一即可 现…

使用mysql、java开发的平台软件一键安装

前言 一般web项目会使用mysql数据库、java开发应用程序打包成jar包。 有些项目会需要导入初始化的行政区域信息。 流程图 说明 1. 脚本中提供变量去配置当前项目的区域 2. 安装包里需要包含全国所有的区域信息 3. 运行程序的时候就可以根据配置 &#xff0c;调用接口&am…

Linux fork 和 exec 联合使用创建一个全新的进程

复制和替换结合在一起&#xff08;forkexec&#xff09;是产生一个新进程的主要方式。 将复制和替换结合在一起&#xff08;forkexec&#xff09;&#xff1a; 先fork&#xff0c;使系统中多出一个进程&#xff0c;默认情况下&#xff0c;fork之后&#xff0c;父进程和子进程的…

爬虫逆向实战(十四)--某培训平台登录

一、数据接口分析 主页地址&#xff1a;某培训平台 1、抓包 通过抓包可以发现登录是表单提交到j_spring_security_check 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个j_password加密参数 请求头是否加密&#xff1f; 无响应是…

【bug】Unity无法创建项目

bug UnityHub无法创建项目 UnityHub无法创建项目 出现的问题&#xff1a;在创建新项目时弹出来一个 无法创建项目 尝试的方法&#xff1a; 刷新许可证 ❌没用退出账号重新登陆 ❌没用重启电脑 ❌没用 最后发现是什么问题呢&#xff1f; 2021.3.3这个版本我之前在资源管理器中…

mysql binlog 回滚

mysqlbinlog 严格来说mysqlbinlog 不能算回滚&#xff0c;他只是将过去的数据修改记录 重新执行一遍&#xff0c;但是从结果上来看&#xff0c;他也算把数据恢复到任意时间点了&#xff0c;举例来说在昨天的某一刻误删除了一条数据&#xff0c;导致其他数据存储都是异常&#…

C++Qt动态增加垂直滚动条

本博文源于笔者正在工作的一个小内容&#xff0c;内容涉及到为qt动态增加垂直滚动条。文章分为三个部分&#xff0c;问题起源&#xff0c;问题解决方案&#xff0c;问题解决成功效果。思路清晰&#xff0c;文章干货满满&#xff0c;复制源码即可使用。 问题起源 qt中一个页面…

0143 串

目录 4.串 4.1串的定义和实现 4.2串的模式匹配 部分习题 4.串 4.1串的定义和实现 4.2串的模式匹配 部分习题 1.设有两个串S1和S2&#xff0c;求S2在S1中首次出现的位置的运算称为&#xff08;&#xff09; A.求字串 B.判断是否相等 C.模式匹配 D.连…

7-10 奇偶分家

分数 10 全屏浏览题目 切换布局 作者 陈越 单位 浙江大学 给定N个正整数&#xff0c;请统计奇数和偶数各有多少个&#xff1f; 输入格式&#xff1a; 输入第一行给出一个正整N&#xff08;≤1000&#xff09;&#xff1b;第2行给出N个非负整数&#xff0c;以空格分隔。 输…

DNNGP模型解读-early stopping 和 batch normalization的使用

一、考虑的因素&#xff08;仅代表个人观点&#xff09; 1.首先我们看到他的这篇文章所考虑的不同方面从而做出的不同改进&#xff0c;首先考虑到了对于基因组预测的深度学习方法的设计 &#xff0c;我们设计出来这个方法就是为了基因组预测而使用&#xff0c;这也是主要目的&…