LeetCode 排序经典题型

Leetcode经典排序题思路

169. 多数元素

题目链接Leetcode169

题解

1.投票算法

根据题意可以得知,本题保证在所给的数组里,所求元素的数量一定超过一半。那么我们可以联想到选举投票。假设不同的元素代表不同的候选人,一一对应。我们要选举的元素票数超过投票人数的一半,假定这个元素一定存在。因为各元素的关系是互相对立的,因此一定是可以进行互相抵消的,两两抵消,最终剩下的元素就一定是当选元素了。
为什么呢?
我们假设最极端的情况为所有落选的元素都站在当选元素的对立面,当所有落选元素都被抵消时,因为当选元素票数多于总票数一半,所以一定会剩下至少一票是未被抵消的。
我们用代码来实现一下:

class Solution {
public:
	int majorityElement(vector<int>& nums) {
		int count=0;
		int candidate=nums[0];
		for(int num:nums){//一种特殊的for循环用法,不了解可以百度
			if(candidate==num)
				count++;
			else{
				if(count>0)
					count--;
				else{
					candidate=num;
					count++;
				}
			}
		}
		return candidate;
	}
};
2.排序

这个问题能出现在排序问题里,则说明它可以用排序的思路解决。
不管元素的大小如何,我们所求的元素出现次数都一定大于总个数的一半。
无论按照什么顺序排列,容器的中位数都一定是我们所求的值。
极端情况:该元素为全部元素中最小或最大值。
那么向另一端延伸都一定会超过中间位置至少一个,因此总数为奇或偶并不影响。
代码实现一下:

class Solution {
public:
	int majorityElement(vector<int>& nums) {
		sort(nums.begin(),nums.end());
		return nums[nums.size()/2];
	}
};

这个方法虽然容易理解,但是时间消耗上会比投票解法要更多一些。

217.存在重复元素

题目链接Leetcode217

题解

本题仍然属于简单题的范畴,可以用库内置的函数sort()来完成。通过上一题排序的解决思路,举一反三。
我们先进行一个排序,然后寻找两个连续相等的数字,若能找到,直接return true,若找不到,再return false
代码如下所示:

class Solution {
public:
	bool containsDuplicate(vector<int>& nums) {
		sort(nums.begin(),nums.end());
		int number=nums[0];
		for(int i=1;i<nums.size();i++){
			if(nums[i]!=number)
				number=nums[i];
			else
				return true;
		}
		return false;
	}
};

75.颜色分类

题目链接Leetcode75

题解

本题要求为原地排序,原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转换资料的算法。当算法执行时,输入的资料通常会被要输出的部分覆盖掉。
因此我们不能使用插入排序来完成本题。
本题不得使用库内置的函数sort()来完成。所以涉及到我们常用的一些排序算法,我们来一一尝试。

1.冒泡排序

这是新手必学的排序方法,如果你和本人一样入门学C++的话,应该很快就会遇到这个方法。
冒泡排序的逻辑是,每一轮通过相邻两个值换位置选出最大的值放到最后,每轮减小一位范畴。
本方法的时间复杂度为 O ( n 2 ) O(n^2) O(n2).
本方法在leetcode上测试的时间复杂度和空间复杂度都表现一般,约超越约50%的人。
代码如下:

class Solution {
public:
	void sortColors(vector<int>& nums) {
		int n=nums.size();
		for(int i=0;i<n-1;i++){
			for(int j=0;j<n-i-1;j++){
				if(nums[j]>nums[j+1]){
					int tmp=nums[j];
					nums[j]=nums[j+1];
					nums[j+1]=tmp;
				}
			}
		}
	}
};
2.选择排序

选择排序与冒泡排序有相似之处,冒泡将最大元素依次浮动到最后一位,而选择排序则是依次将一轮筛选中最小的值与该轮循环的第一个值交换位置,每轮起始位置向后移一位。
同样地,本方法的时间复杂度为 O ( n 2 ) O(n^2) O(n2).
本题代码方案如下:

class Solution {
public:
	void sortColors(vector<int>& nums) {
		int n=nums.size();
		for(int i=0;i<n;i++){
			int tmp=i;
			for(int j=i;j<n;j++){
				if(nums[j]<nums[tmp])
					tmp=j;
			}
			if(tmp!=i)
				swap(nums[tmp],nums[i]);
		}
	}
};
3.快速排序

双指针。

4.特殊方法

引用自:Leetcode用户 颠倒的蝴蝶

根据题意,所有数都≤2,那么索性把所有数组置为2,然后遇到所有≤1的,就再全部置为1,覆盖了错误的2,这时候所有2的位置已经正确,最后所有≤0的全部置为0,也就覆盖了一些错误的1,这时候,0和1的位置都正确。最重要的就是需要两个指针指向下一个1或0的位置。
代码如下所示:

class Solution {
public:
	void sortColors(vector<int>& nums) {
		int n0 = 0, n1 = 0;
		for(int i = 0; i < nums.size(); i++){
			int num = nums[i];
			nums[i] = 2;
			if(num < 2)
				nums[n1++] = 1;
			if(num < 1)
				nums[n0++] = 0;
		}
	}
};

1122.数组的相对排序

题目链接Leetcode1122

题解

本题解法的本质是遍历数组1,和数组2比较,再原地排序。因此,最简单直接的思路是分别遍历两个数组,再设置一个指针,标注排序位置。
代码如下:

class Solution {
public:
	vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {
		int tmp=0;
		for(int i=0;i<arr2.size();i++){
			for(int j=0;j<arr1.size();j++){
				if(arr1[j]==arr2[i]){	
					swap(arr1[j],arr1[tmp]);
					tmp++;
				}
			}
		}
		sort(arr1.begin()+tmp,arr1.end());
		return arr1;
	}
};

389.找不同

题目链接Leetcode389

题解

1.排序+枚举

由于第二个字符串在加入新字母的前提上还是乱序排序的,所以需要一步思路的回溯,也就是先排好序,再找出新字母。但是如果要做到将新字符串排回原先的序,则会消耗比较多的时间,复杂度也更高,考虑到简单粗暴的升降序并不影响我们找出新字母,因此还是可以直接使用sort()直接进行一个升序的排。然后按照字符串的大小一个一个比较,发现不同直接返回,若没有不同,则返回新字符串的最后一位。
代码如下:

class Solution {
public:
	char findTheDifference(string s, string t) {
		sort(s.begin(),s.end());
		sort(t.begin(),t.end());
		for(int i=0;i<t.size();i++){
			if(s[i]!=t[i])
				return t[i];
		}
		return t.back();
	}
};
2.ASCII码之差

我愿称之为本题众多解法中最为诡异又巧妙的做法。

引用自Leetcode用户 冰可乐泡枸杞🍉

话不多说上代码:

class Solution {
public:
	char findTheDifference(string s, string t) {
		int ans = 0; 
		for (char ch : t) 
			ans += ch; 
		for (char ch : s) 
			ans -= ch; 
		return (char)ans;
	} 
};

Written with StackEdit中文版.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值