笔试面试算法经典--打印数组中相加和为给定值的二元组及三元组(Java)
2017-04-13 21:52
666 查看
【题目】给定一个递增的数组,要求打印数组中和为给定值的二元组,例如: arr[]={-8, -4, -1, 0, 1, 3, 4, 5, 6, 7, 9} , k=10,打印结果为:
1——9
3——7
4——6
思路:利用双重循环遍历数组中的所有二元组,如果二元组相加的值为 k 打印。
解法2(时间复杂度 O(N)空间复杂度 O(1))
思路:优化解法1,利用递增数组的性质,使用两个指针 left ,right 分别指向数组的头和结尾,1.如果 arr[left]+arr[right]==k,则打印,然后left++,right–,因为数组 left—right 之间可能还有满足条件的,2.如果arr[left]+arr[right]
例如上面数组: arr[]={-8, -4, -1, 0, 1, 3, 4, 5, 6, 7, 9} , k=10, 开始时left指向-8,right指向9,-8+9=1 小于10,那么left++,指向 -4,-4+9=5小于10,依次到left指向1此时 1+9=10,此时left++指向3,right–指向7,3+7=10符合条件。
解法3(时间复杂度 O(N)空间复杂度 O(N))
思路:解法2中利用了递增数组的性质,如果数组不递增的话,解法2就不能用了。解法3使用一个hashmap将前面遍历过的值保存起来,后面遍历到arr[j]时到hashmap中找 有没有 值为k-arr[j]的元素,如果有则打印,因为在hashmap中根据key查找只需要O(1)的时间所以算法的时间复杂度为O(N)。用hashmap还有一个好处就是可以去掉重复的二元组。
思路:跟上面的二元组解法1的思路类似,使用三重循环,遍历数组的每一个三元组,如果其和为给定值,则将其打印。
解法2(时间复杂度O(N * N * N)空间复杂度 O(1))
思路:解法1 显然不是一个好方法,利用递增数组的性质,类似于二元组的解法2,三元组只用两重循环就能求解,第一重循环用于选择第一个元素,第二重循环子区间中使用二元组的解法2来做,例如arr[i]+arr[j]+arr[k]=sum,只需要在可以转化为求:arr[j]+arr[k]=sum-arr[i],只要在第一重循环中获得arr[i],后面的:arr[j]+arr[k]=sum-arr[i],就是求二元组问题。
1——9
3——7
4——6
1.打印二元组
解法1(时间复杂度 O(N * N)空间复杂度 O(1))思路:利用双重循环遍历数组中的所有二元组,如果二元组相加的值为 k 打印。
public static void twoTuples1(int arr[],int k) { //双重循环遍历每一对双元组 if(arr==null||arr.length==0) return; for(int i=0;i<arr.length-1;i++) for(int j=i+1;j<arr.length;j++) { //如果二元组相加的值为 k则打印 if(arr[i]+arr[j]==k) System.out.println(arr[i]+" "+arr[j]); } }
解法2(时间复杂度 O(N)空间复杂度 O(1))
思路:优化解法1,利用递增数组的性质,使用两个指针 left ,right 分别指向数组的头和结尾,1.如果 arr[left]+arr[right]==k,则打印,然后left++,right–,因为数组 left—right 之间可能还有满足条件的,2.如果arr[left]+arr[right]
<k,则 left++,因为 arr 是递增的 left++后 arr[left]+arr[right]的值将增大,有可能使:arr[left]+arr[right]==k,3.如果arr[left]+arr[right]
>k, right
--。
例如上面数组: arr[]={-8, -4, -1, 0, 1, 3, 4, 5, 6, 7, 9} , k=10, 开始时left指向-8,right指向9,-8+9=1 小于10,那么left++,指向 -4,-4+9=5小于10,依次到left指向1此时 1+9=10,此时left++指向3,right–指向7,3+7=10符合条件。
public static void twoTuples(int arr[],int k) { if(arr==null||arr.length==0) return; int left=0,right=arr.length-1; while(left<right) { if(arr[left]+arr[right]==k) { System.out.println(arr[left]+" "+arr[right]); left++; right--; //arr[left]+arr[right]==k,在left 和 right 之间找符合条件的 } else if(arr[left]+arr[right]<k){ left++; //如果 arr[left]+arr[right]<k ,left++, } else { right--; } } }
解法3(时间复杂度 O(N)空间复杂度 O(N))
思路:解法2中利用了递增数组的性质,如果数组不递增的话,解法2就不能用了。解法3使用一个hashmap将前面遍历过的值保存起来,后面遍历到arr[j]时到hashmap中找 有没有 值为k-arr[j]的元素,如果有则打印,因为在hashmap中根据key查找只需要O(1)的时间所以算法的时间复杂度为O(N)。用hashmap还有一个好处就是可以去掉重复的二元组。
public static void twoTuples2(int arr[],int k) { //使用hashmap进行保存 if(arr==null||arr.length==0) return; HashMap<Integer, Integer> hashMap=new HashMap<Integer, Integer>(); for(int i=0;i<arr.length;i++) { //如果hashmap中存在k-arr[i],的值则打印 if(hashMap.containsKey(k-arr[i])) { System.out.println(k-arr[i]+" "+arr[i]); } //如果hashmap中没有存放arr[i],则将arr[i]的值放入到hashmap中。 if(!hashMap.containsKey(arr[i])) { hashMap.put(arr[i],i); } } }
2.打印三元组
解法1(时间复杂度O(N * N * N)空间复杂度 O(1))思路:跟上面的二元组解法1的思路类似,使用三重循环,遍历数组的每一个三元组,如果其和为给定值,则将其打印。
public static void threeTuples(int arr[],int sum) { //最简单的方法,使用三重循环遍历所有的三元组。 if(arr==null||arr.length<3) return; for(int i=0;i<arr.length-2;i++) for(int j=i+1;j<arr.length-1;j++) for(int k=j+1;k<arr.length;k++) { if(arr[i]+arr[j]+arr[k]==sum) System.out.println(arr[i]+" "+arr[j]+" "+arr[k]); } }
解法2(时间复杂度O(N * N * N)空间复杂度 O(1))
思路:解法1 显然不是一个好方法,利用递增数组的性质,类似于二元组的解法2,三元组只用两重循环就能求解,第一重循环用于选择第一个元素,第二重循环子区间中使用二元组的解法2来做,例如arr[i]+arr[j]+arr[k]=sum,只需要在可以转化为求:arr[j]+arr[k]=sum-arr[i],只要在第一重循环中获得arr[i],后面的:arr[j]+arr[k]=sum-arr[i],就是求二元组问题。
public static void threeTuples2(int arr[],int sum) { //双重循环 if(arr==null||arr.length<3) return; for(int i=0;i<arr.length-2;i++) { int left=i+1,right=arr.length-1; while(left<right) { if(arr[i]+arr[left]+arr[right]==sum) { System.out.println(arr[i]+" "+arr[left]+" "+arr[right]); left++; right--; } else if(arr[i]+arr[left]+arr[right]<sum) { left++; } else { right--; } } } }
相关文章推荐
- 笔试面试算法经典-找到数组中出现次数大于N/k的数(Java)
- 不重复打印排序数组中相加和为给定值的所有二元组和三元组
- 左神算法 不重复打印排序数组中相加和为给定值的所有二元组
- 笔试面试算法经典-未排序正整数数组中累加和为给定值的子数组
- 笔试面试算法经典--连续子数组的最大乘积及连续子数组的最大和(Java)
- 笔试面试算法经典-打印n个数组中最大的topk
- 笔试面试算法经典--数组partition调整使数组的左部分单调有序
- 【LeetCode-面试算法经典-Java实现】【004-Median of Two Sorted Arrays(两个排序数组的中位数)】
- 【LeetCode-面试算法经典-Java实现】【026-Remove Duplicates from Sorted Array(删除排序数组中的重复元素)】
- 笔试面试算法经典--二叉树层次打印
- 【LeetCode-面试算法经典-Java实现】【088-Merge Sorted Array(合并排序数组)】
- 笔试面试算法经典--二叉树的子结构(Java)
- 【LeetCode-面试算法经典-Java实现】【108-Convert Sorted Array to Binary Search Tree(排序数组转变为平衡二叉树)】
- 【LeetCode-面试算法经典-Java实现】【053-Maximum Subarray(最大子数组和)】
- 笔试面试算法经典--矩阵的最短路径和(Java)
- 笔试面试算法经典--二叉搜索树转有序的双向链表(Java)
- 【LeetCode-面试算法经典-Java实现】【152-Maximum Product Subarray(子数组的最大乘积)】
- 【LeetCode-面试算法经典-Java实现】【053-Maximum Subarray(最大子数组和)】
- 【LeetCode-面试算法经典-Java实现】【154-Find Minimum in Rotated Sorted Array II(找旋转数组中的最小数字II)】
- 【LeetCode-面试算法经典-Java实现】【189-Rotate Array(旋转数组)】