121.买卖股票的最佳时机
1.这道题看了的第一想法就是暴力求解…
- 定义一个变量来存放当前最大差值,遍历数组中每个数,与它之后的每个大于它的数进行求差
- 遍历完后变量中存放的就是最大差值了,但这样的想法一上来就应该避免,因为复杂度太高O(n^2),但是想了很久也没有更简单的做法(还是做题少)
//击败9%
public int maxProfit(int[] prices) {
int sum = 0;
for (int i = 0; i < prices.length - 1; i++) {
for (int j = i + 1; j < prices.length; j++) {
if (prices[i] < prices[j]) {
int sum1 = prices[j] - prices[i];
if (sum < sum1) {
sum = sum1;
}
}
}
}
return sum;
}
2.寻求思路的过程中,发現有个思路比较简便,而且做法清晰
- 寻求当前最小峰值当前的最大差值:用两个变量,一个用来存放当前最小,一个用来存放差值
- 在一次遍历的过程中通过不断移动指针来比较得出当前最小值,如果不是最小值就计算与其差值,差值再与存放差值的变量比较,得出最大差值。
- 复杂度为O(n),用的是我认为“边走边看”的思想。我觉得精髓还是在于变量存储的是什么,以及在一次遍历过程中完成的任务。
//击败99.9%
public int maxProfit(int[] prices) {
int min = 0;
if (prices.length > 0)
min = prices[0];
int sum = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < min) {
min = prices[i];
} else {
if (prices[i] - min > sum) {
sum = prices[i] - min;
}
}
}
return sum;
}
169.求众数
1.练习用Hashset存放
- 最近练习的时候,发现了自己的思维局限,总是依赖于暴力求解for套for,所以有意识的用之前借鉴的别人的方法和思路来看待问题,希望能够在刷题过程中养成新的思维习惯,能够从更多角度看待问题
在我之前的一道题中,有人的方法提到了HashSet,于是我就去复习了相关的关于容器的知识。所以这道题 - 分析完了之后,发现可以用key- value来记录某些数出现的次数,使用Hashmap
当然前提是有序数组,所以先排序,排完后用一个变量n来记录当前的值的第一个位置,用i++去遍历它的次数 - 如果第i个数不是第n个元素对应的值,那么就说明这个值的次数已经得到了,将它存入map中,最后遍历map的value值找到最大,返回其key值即可(当然还要考虑最后一个元素时的特殊情况,如果与前面相等就将次数加一,否则就put新值)。
- 虽然这样做可能有些麻烦,但是也算是练习了hashmap,更加了解了hashmap的使用场景,改变我的固定思维
// 35%
public void majorityElement(int[] nums) {
Arrays.sort(nums);
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
int n = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != nums[n] || i == nums.length - 1) {
if (i == nums.length - 1 && nums[i] == nums[n]) {
i++;
} else {
map.put(nums[i], 1);
}
map.put(nums[n], i - n);
n = i;
}
}
int nn = 0;
int max = 0;
for (Integer key : map.keySet()) {
if (map.get(key) > max) {
nn = key;
max = map.get(key);
}
}
System.out.println(nn);
}
2.还有一种方法也叫“蠕虫思想”
- 其实跟上面2的方法类似,不过是设置变量存放当前最符合的值而忽略其余
//15%
public int majorityElement(int[] nums) {
Arrays.sort(nums);
System.out.println(Arrays.toString(nums));
int n = 1;
if (nums.length == 1) {
return nums[0];
}
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == nums[i + 1]) {
n++;
if (n > nums.length / 2) {
return nums[i];
}
} else {
n = 1;
}
}
return -1;
}
3.借鉴解题区的优质方法(最简单易懂):
- 直接排序输出中间数(由于这里众数的定义为超过数组1/2,同时题中给出的数字总有众数,故排序后中间的数绝对为中位数)。
- 没想到代码可以写的这么优雅,这可能就是算法的魅力吧
//96%
public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
217.存在重复元素
1.分析之后,不难想出
-
将其中元素逐个遍历,对比他与剩下的元素是否有相同的,相同就返回true,否则返回false
-
可这样的复杂度是O(n^2),有没有更好的办法呢
//5%
public boolean containsDuplicate(int[] nums) {
for(int i = 0;i<nums.length-1;i++) {
for(int j = i+1;j<nums.length;j++) {
if(nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
2.再来读题
- 如果这是个有序的数组,那么,判断是否有重复元素只需比较当前元素和它的下一个元素,再将指针后移,遍历整个数组
- 如果相同,就立即返回true,否则就返回false,这样复杂度就直接降到了O(n)
//89%
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for(int i = 0;i<nums.length-1;i++) {
if(nums[i] == nums[i+1]) {
return true;
}
}
return false;
}
3.在做完后,查看了其他人的题解,想要借鉴更好的思路,发现一个比较有意思的做法:
- 由于HashSet具有不能存放重复元素的特性,故将数组中的元素一一存入
- 若存入失败,则说明元素在HashSet中已经存在,则返回true,否则false
- 这样的复杂度同样是O(n),但是却巧妙的利用了容器的特性,容器既然学了它的用法,就要学会学以致用,熟悉它的各种方法,用的多了自然会熟练
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for(int i:nums) {
if(!set.add(i))
return true;
}
return false;
}