算法: 和为 K 的子数组
给你一串数据1,2,3,4,5,再给你一个数据 k =5,请你用代码写出连续的,并且和为k的子数组。
咱这就是夸夸一顿写
public class LH560 {public static void main(String[] args) {int[] nums = new int[]{1,2,3};int k =3;int left =0;int result =0;while(left<nums.length){int num = nums[left];if(num == k){result = result +1;for(int index =left+1; index<nums.length; index++){if(nums[index] ==0){result = result +1;}}}else{int right =left +1;result = recyle(right, nums, k, result, num);}left = left+1;}System.out.println(result);}public static int recyle(int right, int[] nums, int k, int result, int num){while(right < nums.length){int i = nums[right] + num;if(i != k){right = right+1;result = recyle(right, nums,k ,result ,i);right = nums.length+1;}else{result = result+1;Label:for(int index =right+1;index < nums.length; index ++){if(nums[index] == 0){result = result+1;}else{break Label;}}right = nums.length+1 ;}}return result;}}
整体流程是这样的:
调试了几个例子,成功,提交代码。
什么?没有通过?目标数据我来调试一下,啊,原来是忘记考虑这种情况了,好了。
什么又没通过? 我再看看,原来是忘记接收值了。这些总没问题了吧。
什么又没通过?这个数据,算了,看答案吧,不想调试这个了。
于是把我的代码丢给元宝看看哪里有问题?
元宝的答案好像冬日里的暖宝宝,给我一个大大的安慰。
元宝和官方给出的答案都长这样:
public class LH560_1 {public static void main(String[] args) {int[] nums = new int[]{1,2,3};int k =3;int count = 0, pre = 0;HashMap< Integer, Integer > mp = new HashMap < > ();mp.put(0, 1);for (int i = 0; i < nums.length; i++) {pre += nums[i];if (mp.containsKey(pre - k)) {count += mp.get(pre - k);}mp.put(pre, mp.getOrDefault(pre, 0) + 1);}System.out.println(count);}
看不懂,让元宝解释一下:
使用了前缀和
依然不懂,但是元宝这里有句话犹如醍醐灌顶:
这样再一看,比如 12345,map里面存的数据为 {0,1},{1,1},{3,1},{6,1},{10,1},{15,1}。
在这里我们要找k'=5,就是{2,3} 和{5} ,而这时的pre=6和15, 6-5找到了{1,1},而{1,1}和pre为6刚好是2和3的两个连续数字的和,也可以看成是6和1这两个前缀和的差,如果这里不是2和3,是2和2,那么这里pre就是5,5-5=0,也有{0,1},所以这里也是可以取到0,1,相当于前三个数据的差;倘若是1,10,0,5 那么 map里面存的数据就为{0,1},{1,1},{11,2},{16,1},而这里pre只有在为16时,可以得到16-5等于11,拿取其中11对应的value2,正是{0,5}和{5}。
果然是相当于两个前缀和的差。
好了基础的1,2,3,4,5的例子你已经通过了,接下来是小小的课堂实验,请调试一下这个例子:
key =-93