LeetCode 算法系列:第 21 ~ 25题

目录
21. 合并两个有序链表
22. 括号生成
23. 合并K个排序链表
24. 两两交换链表中的节点
25. K 个一组翻转链表

21. 合并两个有序链表

题目描述

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

输入:1->2->4, 1->3->4

输出:1->1->2->3->4->4

思路

      我们可以用迭代的方法来实现上述算法。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

算法:

      首先,我们设定一个哨兵节点 prehead ,这可以在最后让我们比较容易地返回合并后的链表。

     我们维护一个 prev 指针,我们需要做的是调整它的 next 指针。然后,我们重复以下过程,直到 l1 或者 l2 指向了 null :

如果 l1 当前节点的值小于等于 l2 ,我们就把 l1 当前的节点接在 prev 节点的后面同时将 l1 指针往后移一位。否则,我们对
l2 做同样的操作。不管我们将哪一个元素接在了后面,我们都需要把 prev 向后移一位。在循环终止的时候, l1 和 l2 至多有一个是非空的。

      由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表即可。

c++版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode * l = new ListNode(-1);
        ListNode * p = l;
        while(l1 and l2){
            if(l1->val < l2->val){
                p->next = l1;
                p = p->next;
                l1 = l1->next;
            }
            else{
                p->next = l2;
                p = p->next;
                l2 = l2->next;
            }
        }
        if(l1)p = p->next = l1,l1 = l1->next;
        if(l2)p = p->next = l2,l2 = l2->next;
        return l->next;
    }
};

python版本

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def mergeTwoLists(self, l1, l2):
        l = ListNode(-1);
        p = l
        while(l1 or l2):
            if l1 == None:
                p.next = ListNode(l2.val)
                p = p.next
                l2 = l2.next
            elif l2 == None:
                p.next = ListNode(l1.val)
                p = p.next
                l1 = l1.next
            else:
                if l1.val < l2.val:
                    p.next = ListNode(l1.val)
                    p = p.next
                    l1 = l1.next
                else:
                    p.next = ListNode(l2.val)
                    p = p.next
                    l2 = l2.next
        return l.next
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """

22. 括号生成

题目描述

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例

输入:n = 3

输出:[

“((()))”,

“(()())”,

“(())()”,

“()(())”,

“()()()”

]

思路

递归:
1.使用递归。
2.每次可以放置左括号的条件是当前左括号的数目不超过 n。
3.每次可以放置右括号的条件是当前右括号的数目不超过左括号的数目。

c++代码

class Solution {
public:
    vector<string>ans;
    vector<string> generateParenthesis(int n) {
      dfs(n,0,0,"");
      return ans;
    }
    void dfs(int n ,int l,int r,string sep)
    {
        if(l==n&&r==n)
            ans.push_back(sep);
        else
        {
          if(l<n)
            {
                dfs(n ,l+1,r,sep+"(");
            }
        if(r<n&&l>r)
          {
            dfs(n ,l,r+1,sep+")");
          }
        } 
    }
};

python 代码

class Solution(object):
    def generateParenthesis(self, n):
        ans = []
        def dfs(n, l, r, s):
            if l == n and r == n:
                ans.append(s)
            else:
                if l < n:
                    dfs(n, l + 1, r, s + '(')
                if r < n and l > r:
                    dfs(n, l, r + 1, s + ')')
                    
        dfs(n, 0, 0, "")
        return ans
        """
        :type n: int
        :rtype: List[str]
        """

23. 合并K个排序链表

题目描述

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入: [ 1->4->5, 1->3->4, 2->6 ]
输出: 1->1->2->3->4->4->5->6

思路

使用优先队列合并:
我们需要维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,
每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。

c++代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:

    struct cmp{
        bool operator()(ListNode* a, ListNode* b){
            return a->val > b->val;
        }
    };
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*,vector<ListNode*>,cmp> heap;
        ListNode* dummy = new ListNode(-1);
        ListNode* tail = dummy;
        for(auto l : lists) if(l) heap.push(l);
        while(heap.size()){
            auto t = heap.top();
            heap.pop();
            tail = tail->next = new ListNode(t->val);
            t = t->next;
            if(t) heap.push(t);
        }
        return dummy->next;
    }
};

python代码

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def mergeKLists(self, lists):
        import heapq
        heap = []
        for node in lists:
            while node:
                heappush(heap, node.val)
                node = node.next
        dummy = ListNode(-1)
        p = dummy
        while heap:
            p.next = ListNode(heappop(heap))
            p = p.next
        return dummy.next
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """

24. 两两交换链表中的节点

题目描述

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例:

给定 1->2->3->4, 你应该返回 2->1->4->3.

思路

我们把链表分为两部分,即奇数节点为一部分,偶数节点为一部分,A 指的是交换节点中的前面的节点, B指的是要交换节点中的后面的节点。在完成它们的交换,我们还得用 prevNode 记录 A 的前驱节点。 算法:
1.firstNode(即 A) 和 secondNode(即 B) 分别遍历偶数节点和奇数节点,即两步看作一步。
2.交换两个节点:firstNode.next = secondNode.next; secondNode.next = firstNode
3.还需要更新 prevNode.next 指向交换后的头:prevNode.next = secondNode
4.迭代完成后得到最终的交换结果。

c++代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        ListNode* p = dummy;
        while(p->next && p->next->next){
            auto a = p->next;
            auto b = a->next;
            p->next = b;
            a->next = b->next;
            b->next = a;
            p = a;
        }
        return dummy->next;
    }
};

python 代码

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution(object):
    def swapPairs(self, head):
        dummy = ListNode(-1)
        dummy.next = head
        p = dummy
        while p.next and p.next.next:
            a = p.next
            b = a.next
            p.next = b
            a.next = b.next
            b.next = a
            p = a
        return dummy.next
        """
        :type head: ListNode
        :rtype: ListNode
        """

25. K 个一组翻转链表

题目描述

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。 k 是一个正整数,它的值小于或等于链表的长度。 如果节点总数不是 k的整数倍,那么请将最后剩余的节点保持原有顺序。

示例:

给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回:3->2->1->4->5

说明: 你的算法只能使用常数的额外空间。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

思路

(模拟) O(L):
1.增加虚拟头结点 dummy,并且令 cur 指针指向 dummy。
2.对于每一轮的修改,令 first 指针为 cur->next,并求出 end 指针为下一轮需要交换的最后一个结点; 在找 end 的过程中,若不足 k 个结点,则直接终止循环。
3.在找到 first 和 end 后,设置 p1 和 p2 两个指针修改相邻结点之间的连接关系,需要一个临时的 new_p2 指针。
4. 最终修改 cur->next 和 first->next。
5.令 cur 指向下一轮修改的起始位置的前一个位置。

c++版本

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* nummy = new ListNode(-1);
        nummy->next = head;
        for(auto p = nummy;;){
            auto q = p;
            for(int i = 0; i < k; i++){
                q = q->next;
                if(!q) break;
            }
            if(!q) break;
            auto a = p->next;
            auto b = a->next;
            for(int i = 0; i < k - 1; i++){
                auto c = b->next;
                b->next = a;
                a = b, b = c;
            }
            auto c = p->next;
            p->next = a, c->next = b;
            p = c;
        }
        return nummy->next;
    }
};

python 版本

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
        dummy = ListNode(-1)
        dummy.next = head
        q = dummy
        while(q):
            p = q
            for i in range(0, k):
                p = p.next
                if p == None:
                    break
            if p == None:
                break
            a = q.next
            b = a.next
            for i in range(0, k - 1):
                c = b.next
                b.next = a
                a = b
                b = c
            c = q.next
            q.next = a
            c.next = b
            q = c
        return dummy.next
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值