1-100의 배열에서 누락 된 숫자 찾기

이틀 전 알고리즘 인터뷰를 보니 질문을 써서 직접 올렸어요!

이런 종류의 처리는 실제로 Java에서 직접 새 목록을 생성 한 다음 직접 제거하므로

List<Integer> list = Stream.iterate(1, n -> n + 1).limit(100).collect(Collectors.toList());

        list.remove(list.indexOf(33)); //这里我也想直接写33的,但是数字的话list会自动识别为下标,只能加一层了

        List<Integer> newList = Stream.iterate(1, n -> n + 1).limit(100).collect(Collectors.toList());
        newList.removeAll(list);
        System.out.println("数字:"+JSONArray.toJSONString(newList));

실행 후 거의 문제가 없으며 출력은 누락 된 숫자 인 숫자 배열입니다.

직접 찾고 싶다면 아이디어에 대해 이야기하십시오.

누락 된 값을 찾기위한 가장 쉬운 방법은 순회하는 것이지만이 알고리즘의 복잡성은 O (n)입니다. 일반적으로 알고리즘을 작성할 때는 복잡성을 최대한 줄여야합니다. 숫자를 추측하지만 얼마나 큰지 모를 때 일반적으로 숫자의 범위를 절반으로 줄이고 마지막으로 숫자를 찾습니다. 이렇게하면 숫자를 계산하는 속도는 다음과 같습니다. 데이터의 복잡성은 O (lgN)뿐입니다. 같은 방법으로 존재하지 않는 숫자를 찾기 위해 비슷한 방법을 사용할 수 있습니다.

1-100의 배열을 생성 한 다음 하나를 제거합니다.

  List<Integer> list = Stream.iterate(1, n -> n + 1).limit(100).collect(Collectors.toList());
            list.remove(list.indexOf(i));

누락 된 숫자를 찾는 방법을 정의합니다.

 /**
     *
     * @param numList 缺少数字的数组
     * @param min 数组的最小值
     * @param max 数组的最大值
     * @param initSize 不缺失的话数组的长度(比如1-100应该有100个数。initSize 就是100)
     * @return
     * @throws Exception
     */
    public static Integer findNum(List<Integer> numList,Integer min,Integer max ,Integer initSize) throws Exception{
        // 数组为空,直接返回min,相当于就一个数的数组,还少了一个数,应该不存在这种,方法会做处理
        if(numList.size() == initSize){
            return min;
        }
        // 数组缺少数字,size肯定是小于initSize 的,如果大于,肯定是有问题了
        if(numList.size()> initSize){
            throw new Exception("数组个数大于传递个数,缺失暂时无法计算!");
        }

        Integer minNum = numList.get(0); // 获取数组实际的最小值
        Integer maxNum = numList.get(numList.size() - 1); // 获取数组实际的最大值

        //对比,不一样的话直接返回最小值或者最大值
        if(min != minNum){
            return min;
        }
        if(max != maxNum){
            return max;
        }

        //数组个数奇数偶数区分,奇数偶数肯定有不同的处理逻辑
        int midNum ;  // 中间的那个值,奇数组与偶数组定义不同
        boolean flag = false;// 数组个数是不是偶数
        if((initSize)%2==0){
             midNum = (maxNum + minNum) / 2;
             flag = true;
        } else {
            midNum = (maxNum + minNum) / 2;
        }
        // 中间的那个值为空,直接返回,说明缺少这个中间数
        int i = numList.indexOf(midNum);
        if(i == -1){
            return midNum;
        }


        if(flag){// 偶数个数的数组处理
            // 从第一个到中位数 数组
            List<Integer> preList = numList.subList(0, numList.indexOf(midNum)+1);
            if(preList.size() != initSize/2){  //数组长度不是initSize的一半,说明缺少数字,递归查询
                return findNum(preList,minNum,midNum,initSize/2);
            }
            // 同理,处理后半段
            List<Integer> nextList = numList.subList(numList.indexOf(midNum)+1,numList.size());
            if(nextList.size() != initSize/2){
                return findNum(nextList,midNum+1,maxNum,initSize/2);
            }
        } else {
            //奇数数组处理,取中位数前一位数字,应该等于中位数减一
            Integer midPreNum = numList.get(numList.indexOf(midNum) - 1);
            if(midPreNum != (midNum-1)){
                return midNum -1;
            }
            // 同理,取中位数后一位数字
            Integer midNextNum = numList.get(numList.indexOf(midNum) + 1);
            if(midNextNum != (midNum+1)){
                return midNum + 1;
            }
            //移除中位数
            numList.remove(numList.indexOf(midNum));

            // 取前半段处理,然后递归
            List<Integer> preNumList = numList.subList(0, numList.indexOf(midPreNum)+1);
            if(preNumList.size() < initSize/2){
                return findNum(preNumList,min,midPreNum,initSize/2);
            }
            // 取后半段处理,然后递归
            List<Integer> nextNumList = numList.subList(numList.indexOf(midPreNum)+1,numList.size());
            if(nextNumList.size() < initSize/2){
                return findNum(nextNumList,midNextNum,max,initSize/2);
            }
            // 找不到的话就是没有缺少喽
            System.out.println("数组不缺少值!!");
        }
        return null;

    }

아래 방법 테스트를 작성하십시오.

    public static void main(String[] args) throws Exception {
        
        for (int i = 1; i <=100; i++) {
            List<Integer> list = Stream.iterate(1, n -> n + 1).limit(100).collect(Collectors.toList());
            list.remove(list.indexOf(i));
            Integer num = findNum(list, 1, 100, 100);
            if(i != num){
                System.out.println("num:"+i);
            }
        }
        System.out.println("测试通过~~");
    }
    

1-100 사이의 모든 숫자를 테스트하여 실행 결과를 확인합니다.

测试通过~~

Process finished with exit code 0

알고리즘은 테스트를 견딜 수 있습니다. 알고리즘에 대한 아이디어는 생각하기 어렵지 않지만 구현하면 정말 귀찮습니다. 작성하는 데 50 분이 걸렸고 실행 및 디버그하는 데 20 분 이상이 걸렸고 사라졌습니다. 한 시간 이상. . 알고리즘은 여전히 ​​가장 세부적이고 시간이 많이 걸립니다. .

 

무섭지도, 승리도 없다 !!!

추천

출처blog.csdn.net/zsah2011/article/details/107921657