从今天开始做LeetCode的题目啦,先从简单的开始,同时也开始学习Java。
先从求众数这道题开始吧:求众数-力扣
我最开始的想法是用暴力法:
class Solution { public int majorityElement(int[] nums) { double n = nums.length; double temp=1.0; if(n==1) { return nums[0]; } for(int i=0;i<nums.length;i++) { temp=1; for(int j=i+1;j<nums.length;j++) { if(nums[j]==nums[i]) temp++; } if(temp>=n/2) return nums[i]; } return 0; } }
思路就是穷举,找到出现次数超过一半的数输出,时间复杂度:O(n^2),用了964 ms,远远超过其他人用的时间= =
接着试着用Map来做:
class Solution { public int majorityElement(int[] nums) { Map<Integer, Integer>map=new HashMap<>(); double n=nums.length; for(int i=0;i<nums.length;i++) { if(map.containsKey(nums[i]))//不存在该数字 { map.put(nums[i],map.get(nums[i])+1); if(map.get(nums[i])>n/2) { return nums[i]; } } else { map.put(nums[i],1); } } return nums[0]; } }
这次时间降低的比较多,只用了50 ms,但是发现还是比不过大多数人的算法,于是我点开时间分布来看别人的算法,发现了几个更好的算法,贴在下面:
排序:进行排序之后,因为众数本身出现次数超过整体一半的特性,一定会出现在 n/2 处,开销主要来自快排
class Solution { public int majorityElement(int[] nums) { Arrays.sort(nums); return nums[nums.length/2]; } }
摩尔投票算法:执行时间1ms,时间复杂度:O(n)的神奇算法!看评论有人说是消消乐,太形象了,就是利用众数本身出现次数超过整体1/2,如果把众数记为 +1,把其他数记为 -1,抵消之后肯定大于0,则运用计数器count和一个记录变量,记录下最后一个count > 0的数字就可以了,代码如下:
class Solution { public int majorityElement(int[] nums) { int candi = 0, count = 0; for (int i : nums) { if (count == 0) { count = 1; candi = i; } else { if (i == candi) count++; else count--; } } return candi; } }
此算法也可以延伸到其他考虑出现频率大于某一界限的题目上。