在一个数组中寻找两数相加为n的组合配对数量,需要去重

本文介绍了一种高效算法,用于在数组中寻找和为特定目标值的数对,并统计其出现次数。通过先排序数组,然后采用双指针技术进行遍历匹配,实现了O(n)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

public static final int TARGET = 100;

int isPair(int a, int b) {
  int sum = a+b;
  return sum > TARGET ? 1 : sum < TARGET ? -1 : 0;
}

int countPair(int array[]) {
	//todo
}

这个题目很有意思,在isPair()的方法中,故意用了三目运算的方式绕了一个圈的要表达 sum==100。在java中,compare() 方法的返回规则是:

  1. 两数相等返回0
  2. a>b的时候返回1
  3. a<b的时候返回-1

这里是用了compare()方法的思想来放回比较大小的结果。

  • 在数组中找出相加和为TARGET的2个数,统计他们的组合数量,需要去重,效率小于o(n^2)

解题方法

如果是一个乱序的序列,那么则需要先排序,排序可以用很多中方法,我这里直接调用了Arrays.sort();

package com.jimmy.lib;

import java.util.Arrays;

public class FindSum {

    public static void main(String[] args) {
        int arr[] = {1, 99, 101, 1, 99};

        // 1. 先排序
        Arrays.sort(arr);
        // 2. 开始计算
        int i = countPair(arr);
        System.out.println(i);
    }

    private static final int TARGET = 100;

    private static int isPair(int a, int b) {
        int sum = a + b;
        return sum > TARGET ? 1 : sum < TARGET ? -1 : 0;
    }

    private static int countPair(int array[]) {
        int left = 0;
        int right = array.length - 1;
        int count = 0;

        while (left < right) {

            int pair = isPair(array[left], array[right]);
            if (pair == 0) {
                count++;
                left = addLeft(array, left);
                right = subRight(array, right);
            } else if (pair == 1) {
                right = subRight(array, right);
            } else {
                left = addLeft(array, left);
            }

        }
        return count;
    }

    private static int subRight(int[] array, int right) {
        int lastRight = array[right--];
        while (right >= 0 && array[right] == lastRight) {
            right--;
        }
        return Math.max(right, 0);
    }

    private static int addLeft(int[] array, int left) {
        int lastLeft = array[left++];
        while (left < array.length && array[left] == lastLeft) {
            left++;
        }
        return Math.min(left, array.length - 1);
    }
}
思路
  1. 先排序这个序列
  2. 用2个指针,左右两边开始循环,计算left+right的值是否等于target
  3. 如果相等则 增加left,减少right,记录次数
  4. 如果大于target,则减少right
  5. 如果小于target,则增加left
  6. 去重的关键:就在于如何增加left和如何减少right。
  7. 在增加left的时候,先记录当前的left,如果下一个left和当前的left相同,那就继续增加left
  8. 在减少right的时候,先记录当前的right,如果新的right和当前的right相同,那就继续减少

按照这种思路即可输出序列对。这个应该是快排的思想。

总结

  • 解决数组的题目一般有这几种思想方法:
  1. 先判断数组是否有序,无序则要思考是否先排序后更好解决问题。
  2. 思考有序序列二分查找法是否能否找到解。
  3. 思考快速排序的思想,前后两个指针是否能够找到解。
  4. 思考用从头部或尾部开始的快慢指针的思想是否可以找到解。
  5. 思考堆排序的思想是否可以找到解。
  6. 判断是否和相关,如果相关则记住左子树(left)和右子树(right)的算法
    • 左子树:2*n+1
    • 右子树:2*n+2
  7. 判断是否需要使用位运算中的异或运算
LeavingZzz老师和zijinjun老师挑选了 � n 个礼物,第 � i 个礼物的量为 � � w i ​ 。这些礼物需要装在礼盒里,一个礼盒里只能且必须装两个礼物。 因为礼物是以盲盒的形式发放的,所以两位老师希望每一个礼盒的量是相同的。 在这种情况下,他们想知道,最多可以准备多少个相同量的礼盒。此外,他们也好奇,在保证礼盒数量最多的情况下,礼盒有多少种可能的量(忽略包装盒的量,只考虑礼物的量)。 输入格式 共两行。 第一行为一个 � n, 表示LeavingZzz老师和zijinjun老师准备了 � n 份礼物。 第二行为 � n 个整,第 � i 个整为 � � w i ​ ,表示第 � i 个礼物的量。 输出格式 输出一行。 一行共两个整,第一个表示最多的礼盒数量,第二个整表示在保证礼盒数量最多的情况下,可能的数量。 input1 运行 复制 5 1 10 100 1000 2000 output1 复制 1 10 input2 运行 复制 4 1 2 3 4 output2 复制 2 1 样例解释 样例一:最多准备一个礼盒,礼盒可能的量有: 11 11 101 101 1001 1001 2001 2001 110 110 1010 1010 2010 2010 1100 1100 2100 2100 3000 3000 一共 10 10 种。 样例二:最多准备两个礼盒,礼盒可能的量只有 5 5 一种。 据规模与约定 对于 100 % 100% 的据, 有 2 ≤ � ≤ 10 6 2≤n≤10 6 , 1 ≤ � � ≤ 2000 1≤w i<=2000 ​别告诉我代码
最新发布
07-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值