算法题:元素求和

leetCode -1 ​
leetCode -15

题目一:两数之和,返回下标

Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].

// 方法一:
    public int[] twoSum1(int[] nums, int target) {
        // 利用Map的key-value结构
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int need = target - nums[i];
            if (map.containsKey(need)) {
                // 满足则返回
                return new int[]{map.get(need), i};
            }
            // key=值,value=下标
            map.put(nums[i], i);
        }
        return new int[]{};
    }
    
// 方法二:
    public int[] twoSum2(int[] nums, int target) {
        // 先排序,利用指针
        Arrays.sort(nums);
        // 第一个元素下标
        int l = 0;
        // 最后一个元素下标
        int h = nums.length - 1;
        while (l < h) {
            int sum = nums[l] + nums[h];
            if (sum > target) {
                h--;
            } else if (sum < target) {
                l++;
            } else if (sum == target) {
                // 满足则返回
                return new int[]{l, h};
            }
        }
        return new int[]{};
    }

变形题:返回所有满足条件的两个值,且不重复

Input: nums = [1,3,1,2,2,3], target = 4
Output: [[1,3],[2,2]]

    public static void main(String[] args) {
        int[] nums = new int[]{1,3,1,2,2,3};
        int target = 4;
        List<List<Integer>> result = new ArrayList();
        // 先排序,利用指针
        Arrays.sort(nums);
        // 第一个元素下标
        int l = 0;
        // 最后一个元素下标
        int h = nums.length - 1;
        HashMap<Integer, Integer> valToIndex = new HashMap<>();
        while (l < h) {
            int sum = nums[l] + nums[h];
            int left = nums[l] ; right = nums[h];
            // 求和 大于 目标数,高位往前移一位
            if (sum > target ) {
                // 防止数组越界 && 去重
                if (l < h && nums[h] == right){
                	h--;
                }
            } else if (sum < target ) { // 求和 小于 目标数,低位往后移一位
            	if (l < h && nums[l] == left){
                	l++;
                }
            } else if (sum == target ) {
                // 满足
                if (!valToIndex.containsKey(nums[l])) {
                    valToIndex.put(nums[l], nums[h]);
                    result.add(Arrays.asList(nums[l], nums[h]));
                }
                if (l < h && nums[h] == right){
                	h--;
                }
                if (l < h && nums[l] == left){
                	l++;
                }
            }
        }
        System.out.println(JSONObject.toJSONString(result));
    }

变形:N个数求和:

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]

思路:

    1. 先排序
    1. 利用两数相加的思想,将n个元素,每次固定一个数,递归(n - 1)个数求和,将结果汇总
		public List<List<Integer>> threeSum(int[] nums) {
			// 排序
            Arrays.sort(nums);
            return nSumTarget(nums, 3, 0, 0);
        }
		
		/**
	     * @param nums   数组元素
	     * @param n      元素累加个数
	     * @param index  从数组元素那个下标开始
	     * @param target 元素求和的值
	     */
        public List<List<Integer>> nSumTarget(int[] nums, int n, int index, int target) {
            List<List<Integer>> result = new ArrayList();
            int length = nums.length;
            // 数组的长度小于计算的n个元素操作 || 至少大于两个个元素求和
            if (length < n || n < 2) {
                return result;
            }

            // 两个元素相加
            if (n == 2) {
                // 初始下标
                int i = index;
                // 数组长度
                int j = length - 1;
                while (i < j) {
                    int sum = nums[i] + nums[j];
                    int left = nums[i], right = nums[j];
                    if (sum > target) {
                        // 防止数组越界 && 去重(如果不需要去重则去掉该条件)
                        if (i < j && nums[j] == right){
                            j--;
                        }
                    } else if (sum < target) {
                    	// 防止数组越界 && 去重(如果不需要去重则去掉该条件)
                        if (i < j && nums[i] == left) {
                            i++;
                        }
                    } else {
                        result.add(new ArrayList<>(Arrays.asList(nums[i], nums[j])));
                        // 防止数组越界 && 去重(如果不需要去重则去掉该条件)
                        while (i < j && nums[i] == left) {
                            i++;
                        }
                        // 防止数组越界 && 去重(如果不需要去重则去掉该条件)
                        while (i < j && nums[j] == right) {
                            j--;
                        }
                    }
                }
            } else {
                // 遍历数组,每次取一个元素,从该元素之后的元素看成一个新的数组,进行n-1个元素求和 = target - nums[i]
                for (int i = index; i < length; i++) {
                // 递归:
                    // 参数一:原数组
                    // 参数二:元素个数
                    // 参数三:下标,从第几个元素开始
                    // 参数四:目标值,元素值累加
                    List<List<Integer>> subList = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
                    // 遍历元素,拼接需要的值,
                    for (List<Integer> arr : subList) {
                        // 将 nums[i] 添加到 对应的数组中
                        arr.add(nums[i]);
                        result.add(arr);
                    }
                    
                    // 防止越界 && 过滤当前元素=下一个元素
                    while (i < length - 1 && nums[i] == nums[i + 1]) {
                        i++;
                    }
                }
            }
            return result;
        }
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值