leetcode 22, leetcode 24, leetcode 25

22. 括号生成(中等)

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

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

提示:

1 <= n <= 8


递归

class Solution {
public:
    vector<string> ans;
    vector<string> generateParenthesis(int n) {
        if(n < 0)
            return {};
        dfs(n, "", 0, 0);
        return ans;
    }
    void dfs(int n, string cur, int l, int r)
    {
        //l是当前字符串中的左括号个数,r是右括号个数
        if(r > l) return;
        if(l == n)
        {
            ans.push_back(cur + string(n - r, ')'));
            return;
        }
        dfs(n, cur + '(', l+1, r);
        dfs(n, cur + ')', l, r+1);
    }
};

递归

class Solution {
public:
    vector<string> res;
    vector<string> generateParenthesis(int n) {
        helper("", n, n);
        return res;
    }
    void helper(string cur, int left, int right)
    {
        if(left == 0 && right == 0)
        {
            res.push_back(cur);
            return;
        }    
        if(left > 0)
            helper(cur + '(', left-1, right);
        if(right > left)
            helper(cur + ')', left, right-1);
    }
};

24. 两两交换链表中的节点 (中等)

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。


使用递归来解决该题,主要就是递归的三部曲:

  1. 找终止条件:当递归到链表为空或者链表只剩一个元素的时候,终止。
  2. 找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。
  3. 单次的过程:因为递归是重复做一样的事情,所以从宏观上考虑,只用考虑某一步是怎么完成的。我们假设待交换的俩节点分别为head和next,next的应该接受上一级返回的子链表(参考第2步)。就相当于是一个含三个节点的链表交换前两个节点,就很简单了。

时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。

空间复杂度:O(n),其中 n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。

    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode *newhead = head->next;
        head->next = swapPairs(newhead->next);
        newhead->next = head;
        return newhead;
    }

解法二:迭代

创建哑结点 dummyHead,令 dummyHead.next = head。令 temp 表示当前到达的节点,初始时 temp = dummyHead。每次需要交换 temp 后面的两个节点。

如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。

具体而言,交换之前的节点关系是 temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作。
temp.next = node2
node1.next = node2.next
node2.next = node1
完成上述操作之后,节点关系即变成 temp -> node2 -> node1。再令 temp = node1,对链表中的其余节点进行两两交换,直到全部节点都被两两交换。

两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。

  • 时间复杂度:O(n),其中 n 是链表的节点数量。需要对每个节点进行更新指针的操作。

  • 空间复杂度:O(1)。

    ListNode* swapPairs(ListNode* head) {
        ListNode *dummy = new ListNode(0);
        dummy->next = head;
        ListNode *temp = dummy;
        while(temp->next != nullptr && temp->next->next != nullptr)
        {
            ListNode *node1 = temp->next;
            ListNode *node2 = node1->next;
            temp->next = node2;
            node1->next = node2->next;
            node2->next = node1;
            temp = node1;
        }
        return dummy->next;
    }

25. K 个一组翻转链表

给你一个链表,每 个节点一组进行翻转,请你返回翻转后的链表。

是一个正整数,它的值小于或等于链表的长度。

如果节点总数不是 的整数倍,那么请将最后剩余的节点保持原有顺序。

示例:

给你这个链表:1->2->3->4->5

当 = 2 时,应当返回: 2->1->4->3->5

当 = 3 时,应当返回: 3->2->1->4->5

说明:

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

写一个反转链表的函数,然后递归。

时间复杂度O(n),空间复杂度O(1)。

class Solution {
public:
    ListNode* reverse(ListNode* head, ListNode* tmp)
    {
        ListNode *prev = nullptr, *next = nullptr;
        while(head != tmp)
        {
            next = head->next;
            head->next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
        auto tmp = head;
        for(int i = 0; i < k; i++)
        {
            if(!tmp)
                return head;
            tmp = tmp->next;
        }
        auto newhead = reverse(head, tmp);
        head->next = reverseKGroup(tmp, k);
        return newhead;
    }
};

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页