Lintcode 692
已知:
给一个数组和一个滑动窗口的大小, 求每一个窗口内唯一元素的个数和
示例:
给一个数组 nums = [1, 2, 1, 3, 3] 和 k = 3
第一个窗口为 [1, 2, 1], 只有 2 是唯一的, 计数为 1.
第二个窗口为 [2, 1, 3], 所有的元素都是唯一的, 计数为 3.
第三个窗口为 [1, 3, 3], 只有 1 是唯一的, 计数为 1.
总数为 1 + 3 + 1 = 5
返回 5
思路:
最朴素的思路莫过于给定每个窗口时都重新进行一次计算,得到结果,当然我没那么写,因为题目本身有很明显的递推的关系,只是如何将滑动前一次的数据用到下一次来而已。
在这里,我才用的方法是: 建立一个数组,数组的下标是窗口内元素的值,也就是以示例为例子的话,a[0] = 0, a[1] = 2, a[2] = 1, a[3] = 2
每次窗口滑动时,滑动前第一位数作下标的数组的值-1,滑动后最后一位作下标的数组的值+1.
public class Solution {
public int slidingWindowUniqueElementsSum(int[] nums, int k) {
int max = max(nums);
int[] count = new int[max + 1];
for (int i = 0; i < k && i < nums.length; i++) {
count[nums[i]]++;
}
//会出现nums.length <= k 的情况,也就是窗口比数组大的情况
int ret = calculate(count);
if (nums.length <= k) {
return ret;
}
//滑动
//下标为 滑动后的第一个数-1 的值--
//下标为 滑动后的最后一个数 的值++
for (int i = 1; i <= nums.length - k; i++) {
count[nums[i - 1]]--;
count[nums[i + k - 1]]++;
ret += calculate(count);
}
return ret;
}
private int calculate(int[] count) {
int ret = 0;
for (int i = 0; i < count.length; i++) {
if (count[i] == 1) {
ret++;
}
}
return ret;
}
private int max(int[] nums) {
if (nums.length == 0)
return -1;
int ret = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] > ret) {
ret = nums[i];
}
}
return ret;
}
};
其实请读者思考一下,因为以上代码还有可以优化的地方,也就是说,如果数组为{1,2,3,1000,1000}这样的情况,有没有方法减少calculate函数的工作量呢?
谢谢您的阅读,希望对您有所帮助( • ̀ω•́ )✧