1、题目描述:
给你一个整数数组 nums
。如果任一值在数组中出现 至少两次 ,返回 true
;如果数组中每个元素互不相同,返回 false
。
解题思路:
用了一个HashSet集合来保存数组中出现过的数字。如果在遍历数组时发现某个数字已经在集合中出现过了,就说明数组中至少有两个数字相同,返回true即可。如果遍历完整个数组后都没有发现重复数字,就说明数组中每个元素互不相同,返回false即可。
HashSet
底层是通过HashMap
来实现的,而HashMap
的底层结构为数组+链表,JDK 8
后改为数组+链表+红黑树。
contains方法用来判断Set集合是否包含指定的对象。
语法 boolean contains(Object o)
返回值:如果Set集合包含指定的对象,则返回true;否则返回false。
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums){
if(set.contains(num)){
return true;
}
set.add(num);
}
return false;
}
}
2、题目描述:
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
解题思路 :
使用了一个变量sum来保存当前的子数组和,并使用一个变量maxSum来保存最大的子数组和。在遍历数组时,如果当前子数组和sum加上当前元素nums[i]后仍然大于maxSum,就更新maxSum为sum+nums[i]。如果当前子数组和sum小于0,就将sum重置为0,因为加上一个负数只会使子数组和更小。
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int maxSum = nums[0];
int sum = 0;
for (int i = 0; i < n; i++) {
sum += nums[i];
if (sum > maxSum) {
maxSum = sum;
}
if (sum < 0) {
sum = 0;
}
}
return maxSum;
}
}
当前解法时间复杂度为O(n),进阶分治法解题:
分治思想,将数组分成左右两个部分,分别递归求出左右两个部分的最大子数组和,然后再计算跨越中心点的最大子数组和。最后返回这三个值中的最大值即可。
计算跨越中心点的最大子数组和使用了两个指针从中心点向左和向右分别扫描数组,分别计算左侧和右侧的最大子数组和,然后将它们相加即可得到跨越中心点的最大子数组和。
public int maxSubArray(int[] nums) {
return divideAndConquer(nums, 0, nums.length - 1);
}
private int divideAndConquer(int[] nums, int left, int right) {
if (left == right) {
return nums[left];
}
int mid = left + (right - left) / 2;
int leftSum = divideAndConquer(nums, left, mid);
int rightSum = divideAndConquer(nums, mid + 1, right);
int crossSum = crossSum(nums, left, right, mid);
return Math.max(Math.max(leftSum, rightSum), crossSum);
}
private int crossSum(int[] nums, int left, int right, int mid) {
int leftSum = Integer.MIN_VALUE;
int sum = 0;
for (int i = mid; i >= left; i--) {
sum += nums[i];
leftSum = Math.max(leftSum, sum);
}
int rightSum = Integer.MIN_VALUE;
sum = 0;
for (int i = mid + 1; i <= right; i++) {
sum += nums[i];
rightSum = Math.max(rightSum, sum);
}
return leftSum + rightSum;
}