数组x[]两个数之和等于某个数k,计算所有符合要求的下标组合

一道算法面试题

数组x[],数组里面,两个数之和等于某个数k,计算所有符合要求的下标组合。

解法1:很容易想到双循环法,复杂度O(n^2),查询效率低,但不占用额外的空间。

    public static void twoLoop(){
        int[] x = {1,2,3,6,8,9,12,13,16,18,34,23,25,16,18};
        List<Integer[]> list = new ArrayList<>();

        int length = x.length;
        int y = 10;

        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                if (x[j] == y - x[i]) {
                    list.add(new Integer[]{ i, j });
                }
            }
        }

        list.stream().forEach((s)->
                System.out.println(s[0] + "\t"+s[1])
        );
    }

解法2:牺牲空间换取时间,将数据存入hash表中。复杂度2*O(n)。查询效率高,但空间复杂度增加O(n)。

    public static void twoLoopHash(){
        int[] x = {1,2,3,6,8,9,12,13,16,18,34,23,25,16,18};
        List<Integer[]> list = new ArrayList<>();
        Map<Integer, Integer> map = new HashMap<>();

        int length = x.length;
        int y = 10;

        for (int i=0;i<length;i++){
            map.put(x[i], i);
        }

        //写法一
        /*for (int i=0;i<length;i++){
            int temp = y-x[i];
            if (map.containsKey(temp) && map.get(temp) > i){
                list.add(new Integer[]{map.get(temp), i});
            }
        }*/

        //写法二
        map.forEach((k,v)->{
            int temp = y-k;
            if (map.containsKey(temp) && temp>v){
                list.add(new Integer[]{map.get(temp), v});
            }
        });

        list.stream().forEach((s)->
                System.out.println(s[0] + "\t"+s[1])
        );
    }

解法3: 优化解法2的实现,实现一次循环运算得出结果。

    public static void oneLoopHash(){
        int[] x = {1,2,3,6,8,9,12,13,16,18,34,23,25,16,18};
        List<Integer[]> list = new ArrayList<>();
        Map<Integer, Integer> map = new HashMap<>();

        int length = x.length;
        int y = 10;
        int temp = 0;
        for (int i=0;i<length;i++){
            temp = y-x[i];
            if (map.containsKey(temp)){
                list.add(new Integer[]{map.get(temp), i});
            }

            map.put(x[i], i);
        }

        list.stream().forEach((s)->
                System.out.println(s[0] + "\t"+s[1])
        );
    }

map动态存放数据。

问题:如果数组元素重复怎么办?

解决思路:将数组的下标记录成数组

    public static void twoLoopHashForSameArrayValue(){
        int[] x = {1,2,3,6,8,9,12,13,16,18,34,23,25,16,18,5,5,5,5};
        List<Integer[]> list = new ArrayList<>();
        Map<Integer, List<Integer>> map = new HashMap<>();

        int length = x.length;
        int y = 10;

        for (int i=0;i<length;i++){
            if (map.get(x[i]) == null) {
                map.put(x[i], new ArrayList<>());
            }
            map.get(x[i]).add(i);
        }

        for (int i=0;i<length;i++){
            int temp = y-x[i];
            if (map.containsKey(temp)){
                if (map.get(temp).size()>1){
                    List<Integer> vList = map.get(temp);
                    for (Integer v : vList){
                        if (v>i){
                            list.add(new Integer[]{v, i});
                        }
                    }
                } else {
                    if (map.get(temp).get(0) > i){
                        list.add(new Integer[]{map.get(temp).get(0), i});
                    }
                }
            }
        }

        list.stream().forEach((s)->
                System.out.println(s[0] + "\t"+s[1])
        );
    }

优化一下

public static void oneLoopHashForSameArrayValue() {
        int[] x = {1, 2, 3, 6, 8, 9, 12, 13, 16, 18, 34, 23, 25, 16, 18, 5, 5, 5, 5};
        List<Integer[]> list = new ArrayList<>();
        Map<Integer, List<Integer>> map = new HashMap<>();

        int length = x.length;
        int y = 10;

        for (int i = 0; i < length; i++) {
            int temp = y - x[i];
            if (map.containsKey(temp)) {
                if (map.get(temp).size() > 1) {
                    List<Integer> vList = map.get(temp);
                    for (Integer v : vList) {
                        list.add(new Integer[]{v, i});
                    }
                } else {
                    list.add(new Integer[]{map.get(temp).get(0), i});
                }
            }

            if (map.get(x[i]) == null) {
                map.put(x[i], new ArrayList<>());
            }
            map.get(x[i]).add(i);
        }

        list.stream().forEach((s) ->
                System.out.println(s[0] + "\t" + s[1])
        );
    }

原理分析:MapReduce思想

先将数据转成很多个map,map的key相同,合并value为value数组,map reduce计算

猜你喜欢

转载自blog.csdn.net/fenglllle/article/details/82630909