双重循环用Map替代
求集合的两个数之和的索引
- 愚蠢的做法
- 给定一个整数数组
nums
和一个整数目标值 target
,请你在该数组中找出和为目标值target
的那两个整数,并返回它们的数组下标。
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2]
int diff = 0
for(int i = 0
diff = target - nums[i]
for(int j = 0
if (i == j) {
continue
}
if (nums[j] == diff ) {
res[0] = i
res[1] = j
return res
}
}
}
return res
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] res = new int[2]
//使用map可以保证,key不重复,不用去判断
HashMap<Integer, Integer> maps = new HashMap<>()
for(int i = 0
//获取差值,如果差值作为nums数组中的一个值,并且存在,则直接输出
int diff = target - nums[i]
if(maps.containsKey(diff)) {
//先获取差值的坐标,因为差值排查的是前面填进去的;再获取当前值
res[0] = maps.get(diff)
res[1] = i
return res
}
//key为数组值,value为索引
maps.put(nums[i], i)
}
return res
}
}
寻找两个正序数组的中位数
- 给定两个大小分别为m 和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的中位数。
垃圾解法
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int[] num = new int[nums1.length + nums2.length]
System.arraycopy(nums1,0,num,0,nums1.length)
System.arraycopy(nums2,0,num,nums1.length,nums2.length)
Arrays.sort(num)
int n = (num.length - 1) / 2
if (num.length == 1) {
return num[0]
} else if(num.length % 2 == 0) {
return (num[n] + num[n + 1]) * 0.5
} else {
return num[n]
}
}
}
答案解法
- 二分查找,在两个有序数组中找中位数,假设此时数组长度为
m+n
,那么中位数的位置就是奇数情况(m+n)/2+1
或者偶数情况(m+n)/2和(m+n)/2+1
,排除两个数组中合起来为奇数情况(m+n)/2的个数的数
或者偶数情况(m+n)/2-1的个数的数
。例如m=2 n=3 m+n=5
,中位数位置为3
,那么就要排出两个数组前两个数
,才能找到第3
个;如果m=2 n=3 m+n=6
,中位数位置为3 4
,那么排除两个数组合起来的前两个数
;本质上就是找到两个数组合起来的第k大的数
,排除k-1个数
- 有了上一段的铺垫,可以看出这题的关键就是怎么排除
前几个数
,题解的过程就是不断比较两个数组,排除两个数组的k-1
个数。那就现在就迎来两个问题,每次比较几个数字
和每次排出几个个数
。对于寻找两个数组合起来的第k个位置的数
,理想情况是两个数组长度相等,在每个数字前各取k/2个
,共排除k-1
个;极端情况则是,一个数组中的最小值大于另一个数组的最大值,那么就要把另一个数组的k-1个个数
全部排除。综合下来,为了避免排除错误,每次取两个数组中的k/2
个元素进行比较,也仅排除一个数组的k/2
个元素。
- 理由是,当A数组第
k/2
个元素与B数组第k/2
个元素,有三种情况A的大于B的
,A的小于B的
,A的等于B的
,那么这三种情况无论哪种,都可以排除A或者B的前k/2个元素
,那么此时要找的元素也就是k-k/2
个元素了,以此类推,直到k=1
,此时已经排除了k-1
个数,进行最后一次比较取出最小的,即是目标数。
- 根据数组下标的规则,那么第
k/2
的元素的下标就是k/2-1
。
- 边界情况,
将一个数组全部排除出去
,此时第二个数组此时指向的是下一个数,那么就还需要排除第二个数组k-1
个数,也就是从指向第二个数组的位置,往后数k-1
,这时指向的就是要找的数
- 数组指针移动,第一次为
index=k/2-1
,当比较一次后为index=k/2-1+1 k=k/2
,而由于下一次比较需要向后移动k/2-1
,那么第二次比较的指针newIndex=index+k/2-1
;当index+k/2
越界时,需要取newIndex=length-1
,那么就要取index+k/2与length的最小值
- k的变化,当正常情况下,
k=k-k/2=k-(newIndex-index+1)
,当越界情况下,则要减去剩下的个数length-index
,而此时newIndex=length-1
,那么k=k-(lenght-index)=k-(newIndex-lenght+1)
- 代码
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int length1 = nums1.length, length2 = nums2.length
int totalLength = length1 + length2
if (totalLength % 2 == 1) {
//合起来的数量为奇数,k=(m+n)/2+1
int midIndex = totalLength / 2
double median = getKthElement(nums1, nums2, midIndex + 1)
return median
} else {
//为偶数,k=(m+n)/2和(m+n)/2+1
int midIndex1 = totalLength / 2, midIndex2 = totalLength / 2+1
double median = (getKthElement(nums1, nums2, midIndex1) + getKthElement(nums1, nums2, midIndex2)) / 2.0
return median
}
}
public int getKthElement(int[] nums1, int[] nums2, int k) {
int length1 = nums1.length, length2 = nums2.length
int index1 = 0, index2 = 0
while (true) {
// 边界情况
if (index1 == length1) {
return nums2[index2 + k - 1]
}
if (index2 == length2) {
return nums1[index1 + k - 1]
}
if (k == 1) {
return Math.min(nums1[index1], nums2[index2])
}
// 正常情况
int half = k / 2
int newIndex1 = Math.min(index1 + half, length1) - 1
int newIndex2 = Math.min(index2 + half, length2) - 1
int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2]
if (pivot1 <= pivot2) {
k -= (newIndex1 - index1 + 1)
index1 = newIndex1 + 1
} else {
k -= (newIndex2 - index2 + 1)
index2 = newIndex2 + 1
}
}
}
}