数组
1.求数组的最大子序列和
示例:
//
// 输入: [-2,1,-3,4,-1,2,1,-5,4]
// 输出: 6
// 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
思路分析:(使用动态规划的方法)
这个问题的思考策略就是思考当前位置nums[i]
表示当前位置i的最大子序列和
是否是需要将该位置的下一个位置加进去组成新的最大子序列和。考虑的逻辑也非常好思考:就是如果加入了下一个位置的元素组成的新的最大子序列的和是小于不加入之前的最大子序列的和那么就不加入
总的来说,就是分解子问题,子问题都有相同的解题步骤,使用循环访问到了每一个子问题,在循环中维护了一个当前的最大子序列和
代码实现
class Solution {
public int maxSubArray(int[] nums) {
//先看题目要求,要求O(1)的空间复杂度和O(n)的时间复杂度
//求连续的子序列和,那么就是要看该位置加上下一个位置的值和该位置的值是增大还是减小了
//也就是假如: pre 代表的是当前位置的最大的子序列和
//那么求Math.max(pre+x,x)取大的赋值给当前位置的最大子序列和也就是pre
//用来维护当前位置和当前位置的前一个位置的值
int pre = 0;
//定义初始的最大子序列和为数组的第一个元素
int maxAnx = nums[0];
for( int i = 0; i = nums.length ;i++ ) {
pre = Math.max(pre + nums[i], nums[i]);
maxAns = Math.max(pre,maxAns);
}
return maxAns;
}
}
2.for loop中的i++和++i有什么区别
最近在刷算法题的时候,发现了很多人的算法题解的for loop中很喜欢写成++i而不是i++,到底两者之间有什么区别呢?
特意进行了测试
这个题:
给定一个整数数组,判断是否存在重复元素。
// 如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
class Solution {
public boolean containsDuplicate(int[] nums) {
//注意在for loop中的++i和i++的循环效果都是一样的,但是++i的效率比i++更高,原因是
//i++ 取值 复制 +1 返回
//++i 取值 加一 返回
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; ++i) {
if (nums[i] == nums[i+1])return true;
}
return false;
}
}
这个for loop中的i++和++i的循环效果是一样的,都是先执行,然后在加一再循环。
但是他门之间的效率是有差异的,这也就是很多大佬(大佬都很注意细节)都喜欢在for loop中写++i的原因。
注意在for loop中的++i和i++的循环效果都是一样的,但是++i的效率比i++更高,原因是
i++ 取值 复制 +1 返回
++i 取值 加一 返回
3.寻找数组重复的元素II
//给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
思路:
本道题刚拿到题时,可能会想到暴力解法,使用双层循环访问数组中该位置的元素和该位置之前的所有元素,看是否有相同的元素,但是由于使用双层循环(一层循环控制该元素的位置一直后移,内部的循环控制了要循环访问该位置之前的每个节点),因此时间复杂度是O(n^2)的。
这样的解答超过了要求的时间。
总结:我们希望在访问元素时能在常熟的时间复杂度内实现查询,插入和删除
,然后用单层循环来控制当前元素向后移,该算法的时间复杂度是O(n)的
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(nums[i]))return true;
map.put(nums[i],i);
if (map.size()>k) map.remove(nums[i-k]);
}
return false;
}
}
注意在该算法中有一个小的技巧:既然要求数组中两个元素之间的下标位置不能超过k,那么我们就动态的删除map中的元素使循环时需要判断的元素数变少