问题(共八道)
- 剑指 Offer 03. 数组中重复的数字
- 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
- 剑指 Offer 39. 数组中出现次数超过一半的数字
- 剑指 Offer 45. 把数组排成最小的数
- 剑指 Offer 61. 扑克牌中的顺子
- 快排、堆排:215. 数组中的第K个最大元素
- 桶排序:347. 前 K 个高频元素
- 451. 根据字符出现频率排序
1. 剑指21. 思路
奇数在前,偶数在后,依然是双指针问题。
由于遍历整个数组,时间复杂度为:O(n),原数组中每个元素只遍历一次。由于是原地交换,空间复杂度:O(1)。
解决方案-双指针模板
class Solution {
public int[] exchange(int[] nums) {
int i=0,j=nums.length-1;
if(nums==null) return nums;
while(i<j){
//记得:每一个while都要判断一次i<j or i<nums.length-1,防止数组越界
while(i<j && nums[i]%2!=0){
i++;
}
//i<j or j>0
while(i<j && nums[j]%2==0){
j--;
}
if(i<j){
swap(nums,i,j);
i++;
j--;
}
}
return nums;
}
public void swap(int[] nums,int i,int j){
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}
}
2. 剑指39-思路
解决方案
法1:哈希表
时间复杂度:O(n)。其中 n 是数组 nums 的长度。
空间复杂度:O(n)。哈希表最多包含n- ⌊n/2⌋个键值对,所以占用的空间为 O(n)。这是因为任意一个长度为 n 的数组最多只能包含 n 个不同的值,但题中保证 nums 一定有一个众数,会占用(最少) ⌊n/2⌋+1个数字。因此最多有 n−(⌊n/2⌋+1)个不同的其他数字,所以最多有n- ⌊n/2⌋个不同的元素。
class Solution {
public int majorityElement(int[] nums) {
//计算nums数组出现的个元素个数,记录在哈希表中
Map<Integer,Integer> counts=majorCount(nums);
//记录出现次数最大的元素键值对
Map.Entry<Integer,Integer> majority=null;
for(Map.Entry<Integer,Integer> entry:counts.entrySet()){
if(majority==null || entry.getValue()>majority.getValue()){
majority=entry;
}
}
return majority.getKey();
}
//返回哈希表中value最大数key。其中键值对为:key:nums元素;value:元素出现的次数
public Map<Integer,Integer> majorCount(int[] nums){
//计算nums数组出现的个元素个数,记录在哈希表中
Map<Integer,Integer> counts=new HashMap<Integer,Integer>();
for(int num:nums){
if(!counts.containsKey(num)){
counts.put(num,1);
}else{
counts.put(num,counts.get(num)+1);
}
}
return counts;
}
}
法2:摩尔投票法——空间复杂度上改进
时间复杂度:O(n)。Boyer-Moore 算法只对数组进行了一次遍历。
空间复杂度:O(1)。Boyer-Moore 算法只需要常数级别的额外空间。
class Solution {
public int majorityElement(int[] nums) {
int voted=0,can=0;
for(int num:nums){
if(voted==0){
can=num;
}
voted+=(num==can)?1:-1;
}
return can;
}
}
法3:先排序,找到下标为⌊n/2⌋的元素(下标从 0 开始)一定是众数。
十种排序方法sort以及各方法的复杂度分析
时间复杂度:O(nlogn)。将数组排序的时间复杂度为 O(nlogn)。
空间复杂度:O(logn)。如果使用语言自带的排序算法,需要使用 O(logn)的栈空间。如果自己编写堆排序,则只需要使用 O(1)的额外空间。
//java版本
class Solution {
public int majorityElement(int[] nums) {
int n=nums.length;
//先排序:从小到大
Arrays.sort(nums);
//返回下标为n/2的元素
return nums[n/2];
}
}
//cpp版本
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size() / 2];
}
};