(hash map)Two Sum, sorted(排序+双指针)closest,小于或大于的对数,组成不同的对数
原版 sorted
[抄题]:
[思维问题]:
存sum - nums[i](补集),若出现第二次则调出
[一句话思路]:
hashmap中,重要的数值当做key,角标当做value.
[画图]:
[一刷]:
[总结]:
[复杂度]:n/n
[英文数据结构,为什么不用别的数据结构]:
2根指针 n^2
[其他解法]:2根指针 j=i + 1
[题目变变变]:
class Solution { public int[] twoSum(int[] nums, int target) { int[] result = new int[2]; HashMap<Integer, Integer> map = new HashMap<Integer, Integer>(); for (int i = 0; i < nums.length; i++) { if (map.containsKey(target - nums[i])) { result[0] = map.get(target - nums[i]); result[1] = i; return result; } map.put(nums[i],i); } return result; } }
closest
[抄题]:
找到两个数字使得他们和最接近target
[思维问题]:
j = i + 1, 复杂度平方,不行
[一句话思路]:
排序后,两根指针都往中间走,能比较大小。降低复杂度。
[画图]:
[一刷]:
- corner case是数组长度不足2
- 每一块代码要分开
[总结]:同样是两根指针,用排序可以降低遍历的复杂度
[复杂度]:两根指针是n^2/1
[英文数据结构,为什么不用别的数据结构:
[其他解法]:
[题目变变变]:(都用的排序)返回和小于等于、大于target的对数;3 sum closest
/** * 本参考程序来自九章算法,由 @九章算法 提供。版权所有,转发请注明出处。 * - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。 * - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班, * - Big Data 项目实战班,算法面试高频题班, 动态规划专题班 * - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code */ public class Solution { /** * @param nums an integer array * @param target an integer * @return the difference between the sum and the target */ public int twoSumClosest(int[] nums, int target) { if (nums == null || nums.length < 2) { return -1; } Arrays.sort(nums); int left = 0, right = nums.length - 1; int diff = Integer.MAX_VALUE; while (left < right) { if (nums[left] + nums[right] < target) { diff = Math.min(diff, target - nums[left] - nums[right]); left++; } else { diff = Math.min(diff, nums[left] + nums[right] - target); right--; } } return diff; } }
返回小于、大于的对数
[抄题]:
给定一个整数数组,找出这个数组中有多少对的和是小于或等于目标值。返回对数。
[思维问题]:
不理解cnt为什么是right - left,因为中间的数其实都可以。
有数组先排序。
[一句话思路]:
类似于closest,两边都往中间靠,调节sum的大小。
[画图]:
[一刷]:
- corner case表示不存在的对数时,返回0
- 一定要写排序,不排序啥都完了。类名是Arrays,不是Array。
- 之前的数组[2]是有上下限即可在循环中返回,此时cnt要累积才能返回。
[总结]:
用排序降低复杂度,两边往中间靠。
[复杂度]:
[英文数据结构,为什么不用别的数据结构]:
[其他解法]:
[题目变变变]:
public Class Solution { public int twoSums5(int[] nums, int target) { if (nums.length < 2 || nums.length == null) { return 0; } int left = 0; int right = nums.length - 1; int cnt = 0; Arrays.sort(nums);// while(left < right) { int v = nums[left] + nums[right]; if (v <= target) { left ++; } else { cnt += right - left; right —; } } return cnt; } }
组成不同的对数
[抄题]:
给一整数数组, 找到数组中有多少组 不同的元素对
有相同的和, 且和为给出的 target 值, 返回对数.
[思维问题]:
不知道左右两个指针移动多少。其实是切入点不对:直接从目标v = target切入,大了right--, 小了left++。
corner case是连续的值都相等,nums[right] == nums[right + 1],没想到。
[一句话思路]:
[画图]:
[一刷]:
- 是两边往中间靠,所以nums[right] == nums[right + 1]时,也是right--, 不是++。
[总结]:
closest,小于或大于的对数,组成不同的对数 都是排序+两根指针的做法
[复杂度]:
[英文数据结构,为什么不用别的数据结构]:
[其他解法]:
[题目变变变]:
public class Solution { public int twoSum6(int nums[], int target) { if (nums.length < 2 || nums == null) { return 0; } Arrays.sort(nums); int left = 0; int right = nums.length - 1; int count = 0; int v = nums[left] + nums[right]; while(left < right) { if (v == target) { left++; right—; count++; } while((left < right) && (nums[right] == nums[right + 1])) { right—;// } while((left < right) && (nums[left] == nums[left - 1])) { left++; } } else if(v > target) { right—; } else { left++; } return count; } }