排序专项_快排_合并排序

排序专项_快排_合并排序

1. 合并两个有序链表

题目描述

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

解题思路

思路1:迭代:两个for遍历两个链表,比较val的值,逐个指向较小的数。

  1. 依次比较两条链表的第i个,第j个元素的大小,将新建一个工作节点prev上一次比较大小时的前一个节点,指向比较后较小的那个数对应的节点。

思路2:递归

  1. 比较两条链表的当前节点的大小,记录第一次比较时较小的节点为头节点返回。并使较小的节点指向为递归此函数(较小节点->next, 另一个节点):下一次的递归任务。

源代码

/**
 * 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) {
    
    
        if(!l1)
        {
    
    
            return l2;
        }
        if(!l2)
        {
    
    
            return l1;
        }
        ListNode* head = new ListNode(-1);
        // 迭代是需要一个工作节点的,这里定义一个指针等于另外一个指针(同一类型的指针)
        ListNode* prev = head;
        while(l1 && l2)
        {
    
    
            if(l1->val <= l2->val)
            {
    
    
                prev->next = l1;
                l1 = l1->next;
            }
            else
            {
    
    
                prev->next = l2;
                l2 = l2->next;
            }
            prev = prev->next;
        }
        prev->next = l1 ? l1 : l2;
        return head->next;
    }
};

思路2:

/**
 * 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) {
    
    
        if(!l1)
        {
    
    
            return l2;
        }
        if(!l2)
        {
    
    
            return l1;
        }
        if(l1->val <= l2->val)
        {
    
    
        	l1->next = mergeTwoLists(l1->next, l2);
        	return l1;
		}
		else
		{
    
    
			l2->next = mergeTwoLists(l2->next, l1);
			return l2;
		}
    }
};

题型分析

  1. 合并排序题,可使用递归和迭代的方法解决,递归的方法时间复杂度低很多。

下次遇到此类题我要注意的地方

1. 递归的思想是下一次的任务与这一次的任务相同,只不过改变了参数值而已。2. 迭代的思想可能要定义一个工作指针作为记录。
  1. 定义一个工作指针与头指针相等。
  2. 头指针的next即指向链表的第一个节点。

时间、空间复杂度

思路1:
sf:O(m+n)
kf:O©

思路2:
sf:O(m+n)
kf:O(m+n),递归调用函数

此类题模板代码

  1. 迭代
ListNode* head = new ListNode(-1);
// 迭代是需要一个工作结点的,这里定义一个指针等于另外一个指针(同一类型的指针)
ListNode* prev = head;
while(l1 && l2)
{
    
    
    if(l1->val <= l2->val)
    {
    
    
        prev->next = l1;
        l1 = l1->next;
    }
    else
    {
    
    
        prev->next = l2;
        l2 = l2->next;
    }
    prev = prev->next;
}
prev->next = l1 ? l1 : l2;
  1. 递归
if(l1->val <= l2->val)
{
    
    
    l1->next = mergeTwoLists(l1->next, l2);
    return l1;
}
else
{
    
    
    l2->next = mergeTwoLists(l2->next, l1);
    return l2;
}

启发性或普适性

  1. 递归的思想是相同的任务,不同的参数。
  2. 迭代的思想是工作指针的遍历。

总结

合并排序 = 递归(相同的任务,不同的参数)/迭代(工作指针的遍历)

2. 颜色分类

题目描述

https://leetcode-cn.com/problems/sort-colors/

解题思路

思路1:有一点快排的思想,分别定义0的右边界和2的左边界,遍历数组的值,当遇到2时与2的左边界交换;当遇到0时与0的左边界交换;遇到1时则i++。

  1. 定义好0的右边界和2的左边界。while循环直到i>j。
  2. 当遇到2时与2的左边界交换;当遇到0时与0的左边界交换;遇到1时则i++。

源代码

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int len = nums.size();
        // 0的右边界 
        int le = 0;
        int ri = len - 1;
        int i = 0;
        while(i <= ri)
        {
        	if(nums[i] == 0)
        	{
        		int tmp = nums[i];
        		nums[i++] = nums[le];
        		nums[le++] = tmp;
			}
			else if(nums[i] == 2)
        	{
        		int tmp = nums[i];
        		nums[i] = nums[ri];
        		nums[ri--] = tmp;
			}
			else{
				i++;
			}
		}
    }
};

题型分析

  1. 快排的本质:使用一个递归函数,从数组的左边的数a[i]开始,将数组的数放在一个合适的位置(从左遍历比a[i]大的数,从右遍历比a[i]小的数,交换);将a[i]放置到合适的位置后,a[i]左边的数小于a[i],右边的数大于a[i],再将左边也使用快排,直到i>j。

下次遇到此类题我要注意的地方

1. 快排的本质:将基准数(range)左边的数放到合适的位置,然后递归快排这个位置左边和右边。
  1. 注意在遍历到2时,遍历的索引不需要+1,因为可能交换过来的数还没有放置到正确的位置。遍历到0时,遍历的索引可以+1,因为是从数组的0位置开始遍历的所以左边的a[le]元素就是有序的了。

时间、空间复杂度

思路1:
sf:O(n)
kf:O(1)

思路2:
sf:O()
kf:O()

扫描二维码关注公众号,回复: 11705423 查看本文章

此类题模板代码

  1. 快速排序代码。
int le = 0;
int ri = len - 1;
int i = 0;
while(i <= ri)
{
    
    
    if(nums[i] == 0)
    {
    
    
        int tmp = nums[i];
        nums[i++] = nums[le];
        nums[le++] = tmp;
    }
    else if(nums[i] == 2)
    {
    
    
        int tmp = nums[i];
        nums[i] = nums[ri];
        nums[ri--] = tmp;
    }
    else{
    
    
        i++;
    }
}

启发性或普适性

  1. 快速排序的递归本质:不断将一个数放在一个区间的合适的位置。

总结

颜色分类 = 三色旗问题 + 快排(区间的左右边界+放置到合适的位置)

题目描述

解题思路

思路1:

源代码

题型分析

下次遇到此类题我要注意的地方

时间、空间复杂度

思路1:
sf:O()
kf:O()

思路2:
sf:O()
kf:O()

此类题模板代码


启发性或普适性

总结

猜你喜欢

转载自blog.csdn.net/qq_40092110/article/details/106154375
今日推荐