刷题总结--两数之和系列

题目1–1:两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

来源:力扣(LeetCode)

思路1

暴力求解:
复杂度分析:
时间复杂度:O(n^2)
空间复杂度:O(1)。

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i=0;
        int res[]={0,0};
        while(i<nums.length){
             for(int j=i+1;j<nums.length;j++){
                if(nums[j]==target - nums[i])
                {
                    res[0] = i;
                    res[1] = j;
                }
                  
             }
            i++;
        }
    
        return res;
    }
}

思路2

思路基本一样,只是使用HashMap以空间换取速度的方式,我们可以将查找 target - nums[i]的查找时间从 O(n) 降低到O(1)

代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; i++) {
            int x = target - nums[i];
            if (map.get(x) != null) {
                res[0] = map.get(x);
                res[1] = i;
                return res;
            }
            map.put(nums[i],i);
        }
        return res;
    }
}


题目2–167:两数之和II -输入有序数组

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:

返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:

输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

来源:力扣(LeetCode)

思路

此题相比第一题,多了一个输入条件,就是输入有序数组,因此,我们可以初始化两个指针 low 和 high 分别指向列表的头尾。
从两个方向同时进行迭代,要么找到两数之和的解,要么两个指针相遇。
在每个步骤中,我们将根据不同的条件移动指针:
如果当前指针指向元素的和小于目标值,则应该增加总和来满足目标值,即将 low 指针向前移动获得更大的值。
如果当前指针指向元素的和大于目标值,则应该减少总和来满足目标值,即将 high 向 low 靠近来减少总和。
如果当前指针指向元素的和等于目标值,则直接返回结果。
如果两个指针相交,说明当前列表不存在组合成目标值的两个数。

数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。

代码

class Solution {
public int[] twoSum(int[] numbers, int target) {
    if (numbers == null) return null;
    int i = 0, j = numbers.length - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if (sum == target) {
            return new int[]{i + 1, j + 1};
        } else if (sum < target) {
            i++;
        } else {
            j--;
        }
    }
    return null;
}
}

题目3–170:两数之和 III - 数据结构设计

设计并实现一个 TwoSum 的类,使该类需要支持 add 和 find 的操作。

add 操作 - 对内部数据结构增加一个数。
find 操作 - 寻找内部数据结构中是否存在一对整数,使得两数之和与给定的数相等。

示例 1:

add(1); add(3); add(5);
find(4) -> true
find(7) -> false
示例 2:

add(3); add(1); add(2);
find(3) -> true
find(6) -> false
来源:力扣(LeetCode)
思路:
基于前两道题目的经验,对于find方法,很自然地想到用双指针,从两个方向迭代。
但是要知道,双指针方法的前提条件之一是输入列表有序。

因此,这里我们可以用一个ArrayList来保存我们的数据,同时用boolean型的数值来标记是否有序。当我们调用find()方法的时候,去检查一下,数据是否有序,若无序,则先排序,再用双指针方法去查找当前列表是否存在组合成目标值的两个数。

时间复杂度:

add(number):O(1)
find(value):O(N⋅log(N)),在最坏的情况下,我们需要对列表进行排序和遍历整个列表,这需要O(N⋅log(N)) 和O(N) 的时间。因此总的时间复杂度为O(N⋅log(N))。
空间复杂度:O(N),其中 N 指的是列表中的元素个数。

代码:

    class TwoSum {
    	  private ArrayList<Integer> nums;
    	  private boolean is_sorted;
    	  
     public TwoSum() {
    		    this.nums = new ArrayList<Integer>();
    		    this.is_sorted = false;
    		  }
    		  
     public void add(int number) {
    	    this.nums.add(number);
    	    this.is_sorted = false;
    	  }
    	  
     public boolean find(int value) {
    	    if (!this.is_sorted) {
    	      Collections.sort(this.nums);
    	      this.is_sorted = true;
    	    }
    	    int low = 0, high = this.nums.size() - 1;
    	    while (low < high) {
    	      int twosum = this.nums.get(low) + this.nums.get(high);
    	      if (twosum < value)
    	        low += 1;
    	      else if (twosum > value)
    	        high -= 1;
    	      else
    	        return true;
    	    }
    	    return false;
    	  }


    }

思路:

(这个思路借鉴于力扣解题的某答案)
使用2个HashSet:

all: 负责记录所有元素
duplicate: 负责记录重复的元素
实现方法:

add:如果all中已有该元素,则放入duplicate;否则放入all
find:遍历all中的元素,寻找 target = value - num 是否存在。存在则找到。
这里是否存在分为2种情况判断:

target == num,则在重复元素集合duplicate中找;
target != num,则在所有元素集合all中找。

复杂度分析:

n为已加入的元素个数,
时间复杂度:1次add为O(1),1次find为O(n)
空间复杂度:O(n)

代码:

    class TwoSum {
        private Set<Integer> all;
        private Set<Integer> duplicate;
        
        /** Initialize your data structure here. */
        public TwoSum() {
            all = new HashSet();
            duplicate = new HashSet();
        }
        
        /** Add the number to an internal data structure.. */
        public void add(int number) {
            if (all.contains(number))
                duplicate.add(number);
            else
                all.add(number);
        }
        
        /** Find if there exists any pair of numbers which sum is equal to the value. */
        public boolean find(int value) {
            int target;
            for (int num: all) {
                target = value - num;
                if (target == num && duplicate.contains(target))
                    return true;
                if (target != num && all.contains(target))
                    return true;
            }
            return false;
        }
    }

题目4–653:两数之和 IV - 输入 BST

给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

案例 1:

输入:
5
/
3 6
/ \
2 4 7

Target = 9

输出: True

案例 2:

输入:
5
/
3 6
/ \
2 4 7

Target = 28

输出: False

来源:力扣(LeetCode)

思路

我比较懒,对一个方法会用到底,这个题目和之前的区别就是输入的是一个BST,那我们只需要把输入转换成前面的有序数组就可以了。众所周知,BST的中序遍历是一个递增的有序数列。因此,相比于题目2,只需多一步中序遍历就可以了。

复杂度分析:
时间复杂度:O(n),其中 n 是树中节点的数量。本方法需要中序遍历整棵树。
空间复杂度:O(n),list 中存储 nn 个元素。

代码

    public boolean findTarget(TreeNode root, int k) {
    	if (root == null)
            return false;
    	List<Integer> list = new ArrayList<>();
    	inOrder(root, list);//相比题目2多出来的一步
    	int i = 0, j = list.size() - 1;
        while (i < j) {
            int sum = list.get(i)+list.get(j);
            if (sum == k) {
                return true;
            } else if (sum < k) {
                i++;
            } else {
                j--;
            }
        }
    	return false;
    }
    public void inOrder(TreeNode root, List<Integer> list) {
    	         if(root == null) {
    	             return;
    	         }
    	        inOrder(root.left, list);
    	        list.add(root.val);
    	        inOrder(root.right, list);
  	     }
发布了18 篇原创文章 · 获赞 1 · 访问量 2308

猜你喜欢

转载自blog.csdn.net/Better_WZQ/article/details/104210721