LeeCode题库Solution53、121、217、242、349
Solution53最大子数组和
思路:res作为历史最佳解,sum作为当前最佳解,每一次遍历nums数组时,都去动态更新res和sum。 动态更新的逻辑为: 如果sum为正数,在有res记录历史最佳值的条件下,可以有恃无恐地继续累加,创造新高;如果sum为负数,不管下一次遍历值是多少累加后都不会大于它,见风使舵果断取下一个遍历值为当前最佳解。 每一轮遍历结束后,如果当前最佳解优于历史最佳解,就会升任历史最佳解。 动!!态!!规!!划!!
//如果sum为正数,那么继续向后累加并记录下sum的最大值,继续向后累加的原因是sum有变大的可能。
//如果sum为负数,那么sum+nums[i]必然小于nums[i],所以sum = nums[i].
public int maxSubArray(int[] nums) {
int res = nums[0];
int sum = 0;
for (int num : nums) {
if (sum > 0)
sum += num;
else
sum = num;
res = Math.max(res, sum);
}
return res;
}
Solution121买卖股票的最大收益
动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}
//低价买高价卖
//记录【今天之前买入的最小值】
//计算【今天之前最小值买入,今天卖出的获利】,也即【今天卖出的最大获利】
//比较【每天的最大获利】,取最大值即可
public class S121买卖股票 {
public int maxProfit(int[] prices) {
if(prices.length <= 1)
return 0;
int min = prices[0], max = 0;
for(int i = 1; i < prices.length; i++) {
max = Math.max(max, prices[i] - min);
min = Math.min(min, prices[i]);
}
return max;
}
}
Solution217存在重复元素
方法一 数组排序
排序在对数字从小到大排序之后,数组的重复元素一定出现在相邻位置中。因此,我们可以扫描已排序的数组,每次判断相邻的两个元素是否相等,如果相等则说明存在重复的元素。
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
for (int i = 0; i < n - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
方法二 HashSet
时间空间复杂度都是O(n).
//HashSet 利用哈希表不会存储两个相同元素的特性
public boolean containsDuplicate01(int[] nums) {
HashSet<Integer> hashSet = new HashSet<>();
for (int num : nums) {
if (hashSet.add(num) == false) {
return true;
}
}
return false;
}
Solution242有效字母异位词
import java.util.Arrays;
//给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
public class S242有效的符号 {
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
char[] sChars = s.toCharArray();
char[] tChars = t.toCharArray();
Arrays.sort(sChars);
Arrays.sort(tChars);
return Arrays.equals(sChars, tChars);
}
}
Solution349两数组交集
总结 先排序,然后是用双指针先遍历两容器,重复则插入到新容器
时间复杂度:O(m \log m+n \log n)O(mlogm+nlogn)
细节:对两个数组进行排序,然后使用两个指针遍历两个数组。可以预见的是加入答案的数组的元素一定是递增的,为了保证加入元素的唯一性,我们需要额外记录变量 \textit{pre}pre 表示上一次加入答案数组的元素。
初始时,两个指针分别指向两个数组的头部。每次比较两个指针指向的两个数组中的数字,如果两个数字不相等,则将指向较小数字的指针右移一位,如果两个数字相等,且该数字不等于 \textit{pre}pre ,将该数字添加到答案并更新 \textit{pre}pre 变量,同时将两个指针都右移一位。当至少有一个指针超出数组范围时,遍历结束。
public int[] intersection(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int length1 = nums1.length, length2 = nums2.length;
int[] intersection = new int[length1 + length2];
int index = 0, index1 = 0, index2 = 0;
while (index1 < length1 && index2 < length2) {
int num1 = nums1[index1], num2 = nums2[index2];
if (num1 == num2) {
// 保证加入元素的唯一性
if (index == 0 || num1 != intersection[index - 1]) {
intersection[index++] = num1;
}
index1++;
index2++;
} else if (num1 < num2) {
index1++;
} else {
index2++;
}
}
return Arrays.copyOfRange(intersection, 0, index);
}