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

题目

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. 判断是否需要使用位运算中的异或运算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值