LeetCode.S1
题目:
题目大意:
给定一个数组nums和一个目标值target,输出满足条件(两个数相加等于target)的这两个数的下标,两个数下标不能一样。
PS::该题中一定存在这两个数。
数据范围:
如图所示
一 、笨比解法 :
思路:
将nums数组变成pairs数组(pair<val, pos>,val:值,pos:下标),对pairs数组按照val升序排序(O(nlogn)),遍历pairs数组,当遍历到pairs[i]时,使用二分在pairs数组中查找值为target-pairs[i].val 的pairs[j], 如果pairs[i]的pairs[j]没找到,则往下一个继续找,如果找到了pairs[j]则分情况讨论:
- 如果找到的pairs[j]的坐标pairs[j].pos不等于pairs[i]的坐标pairs[i].pos,符合条件返回[-1, 1]。
- 如果找到的pairs[j]的坐标pairs[j].pos等于pairs[i]的坐标pairs[i].pos,说明找到的是同一个位置上的数,不符合条件,接下来,因为找到的是多个pairs[j].val中最左边的(如果存在多个相同的pairs[j].val话),所以看pairs[j+1].val是否为pairs[j].val,如果不是则说明只存在一个pairs[j].val,则不符合条件,返回[-1,1](再往下找无意义了,比如c的两个因子a,b,找a找b是一样的,a找过了,则b就不用找了)。如果是则说明有多个pairs[j].val,返回[i, j + 1],避免了i = j的情况。
PS:规定如果不存在返回[-1, -1],
代码:
import java.util.Arrays;
class Solution {
public pair[] pairs;
public class pair implements Comparable<pair>{
int a, b;
public pair(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public int compareTo(pair o) {
if (a < o.a)
return -1;
else if (a > o.a)
return 1;
else
return 0;
}
}
public int findX(pair[] nums, int x){
int l = 0, r = nums.length - 1;
while (l < r){
int mid = l + r >> 1;
if (nums[mid].a >= x) r = mid;
else l = mid + 1;
}
if (nums[l].a == x)
return l;
else
return -1;
}
public int[] twoSum(int[] nums, int target) {
pairs = new pair[nums.length];
for (int i = 0; i < nums.length; i ++ ){
pairs[i] = new pair(nums[i], i);
}
Arrays.sort(pairs, 0, pairs.length);
for (int i = 0; i < pairs.length; i ++ ){
//如果有多个j,返回最左边的j
int j = findX(pairs, target - pairs[i].a);
//找到最左边的
if (j != -1)
{
if (pairs[i].b == pairs[j].b){
if (j + 1 < pairs.length && pairs[i].a == pairs[j].a)
return new int[]{pairs[i].b, pairs[j + 1].b};
else
return new int[]{-1, -1};
}else{
return new int[]{pairs[i].b, pairs[j].b};
}
}
}
return new int[]{-1, -1};
}
}
public class Main {
public static void main(String[] args) {
int target = 3;
int[] nums = new int[]{1, 3, 2};
Solution solution = new Solution();
System.out.println(Arrays.toString(solution.twoSum(nums, target)));
}
}
时空复杂度分析等:
- 时间复杂度 : O(nlogn)
- 空间复杂度 : O(n)
二 、解法 :
思路:
使用HashMap,将查找的时间复杂度从O(logn)降为O(1),在遍历nums数组时,先查看hashmap<val, pos>的key中有无nums[i]所对应的target-nums[i],如果有,返回{hashMap.get(target - nums[i]), i},如果没有,则将(nums[i], i)加入hashMap中。
最后如果没找到则返回{-1,-1}。
代码:
class Solution{
public int[] twoSum(int[] nums, int target){
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i ++ ){
if (hashMap.containsKey(target - nums[i])){
return new int[]{hashMap.get(target - nums[i]), i};
}else{
hashMap.put(nums[i], i);
}
}
return new int[]{-1, -1};
}
}
public class Main {
public static void main(String[] args) {
int target = 6;
int[] nums = new int[]{1, 3, 3};
Solution solution = new Solution();
System.out.println(Arrays.toString(solution.twoSum(nums, target)));
}
时空复杂度分析等:
- 时间复杂度 : O(n)
- 空间复杂度 : O(n)
附:
HashMap 遍历 以及神奇操作
Set<Map.Entry<Integer, Integer>> entries = hashMap.entrySet();
for (Map.Entry<Integer, Integer> entry : entries){
System.out.println(entry.getKey() + ", " + entry.getValue());
entry.setValue(-1);
}
System.out.println("!!!");
Set<Map.Entry<Integer, Integer>> entries1 = hashMap.entrySet();
for (Map.Entry<Integer, Integer> entry : entries1){
System.out.println(entry.getKey() + ", " + entry.getValue());
}
/*
1, 0
3, 1
4, 3
!!!
1, -1
3, -1
4, -1
*/