LeetCode链表处理集锦(二)

21.合并两个有序链表
题目描述:
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
个人思路:
两个链表遍历,挨个比较,然后依次连接到新的链表上,递归即可。
代码实现:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode *NewNode;
        if(!l1)
            return l2;
        if(!l2)
            return l1;
        if(l1->val < l2->val)
        {
            NewNode = l1;
            NewNode->next = mergeTwoLists(l1->next, l2); 
        }
        else
        {
            NewNode = l2;
            NewNode->next =  mergeTwoLists(l1, l2->next);
        }
        return NewNode;
    }
};

结果显示:
在这里插入图片描述
---------------------------------------------------------------------------------5月19日
148.排序链表
题目描述:
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5

思路:
排序方式有很多种,快速排序、堆排序、桶排序、归并排序等等,这里符合时建锋复杂度以及单链表形式的,是归并排序。
归并排序主要原理就是
2 8 11 6 77 22 3
(1)2 8 6 11 22 77 3
(2)2 6 8 11 22 77 3
(3)2 3 6 8 11 22 77
分治:将链表分为两段,一段用slow,一段用fast。slow每次走一步,fast每次两步。
代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (!head || !head->next)
            return head;
        ListNode *slow = head, *fast = head, *pre = head;
        while (fast && fast->next) {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = NULL;
        return merge(sortList(head), sortList(slow));
    }
    ListNode* merge(ListNode* l1, ListNode* l2) {
        ListNode *dum = new ListNode(-1);
        ListNode *cur = dum;
        while (l1 && l2) {
            if (l1->val < l2->val) {
                cur->next = l1;
                l1 = l1->next;
            } else {
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        if (l1) cur->next = l1;
        if (l2) cur->next = l2;
        return dum->next;
    }
};

结果:
在这里插入图片描述
---------------------------------------------------------------------------------5月27日
61.旋转链表
题目描述:
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL

示例 2:

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

思路:
首先存储下链表的长度,然后将单链表构造成循环链表,最后判断断开的位置,将循环链表拆成单链表。
循环链表时,根据k和len可以判断出移动位置,k%len可以去除掉多余的重复的几圈,减少移动次数,最终的取余值 一开始我以为直接是循环次数,实际上不是,用len-k+1才是循环的位置,很好理解。
还有就是p始终都是存储结尾最后一个结点,所以最后让p指向null就可以将链表拆开。
代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == NULL) return head;
        ListNode* p = head;
        int len = 1;//记录长度
        while(p->next)
        {
            p = p->next;
            len++;
        }
        p->next = head;//构建循环链表
        //判断移动位置
        k %= len;
        //判断断开位置
        for(int i = 1; i <  k ; i++)
        {
            p = p->next;
            head = head->next;
        }
        p->next = NULL;//断开循环链表,成为单链表
        return head;
    }
};

结果:
在这里插入图片描述
----------------------------------------------------------------------------------5月28日
235.二叉搜索树的最近公共祖先
题目描述:
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
在这里插入图片描述
示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

思路:
如果root的值大于p、q的值,那p、q的公共祖先肯定在左枝,反之亦然,若root在p、q之间事,那root就是最近公共祖先。

代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * }; 
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 			  {
        if(root == NULL) 
            return NULL;
        bool flag = true;
        while(flag){
        if(root->val >  p->val && root->val >  q->val )
            root = root->left;
        else if(root->val <  p->val && root->val <  q->val )
            root = root->right;
        else
            flag = false;
        }
        return root;
    }
};

--------------------------------------------------------------------------------------------------6月5日

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值