算法题目:假如一个订单的编码规则是AAAAOrder2020-0000001,AAAAOrder2020-0000002

题目:假如一个订单的编码规则是AAAAOrder2020-0000001,AAAAOrder2020-0000002,后面的数字是自增长,如果订单号码达到AAAAOrder2020-1000000(一百万)时,数据库中应该有100万条数据,此时我随机删除两条数据(物理删除,且不考虑备份和日志),请问怎么找到删除的数据编码?给出解题思路,答案要求在1秒内运行得到。

*今天看到群里有人问了一道这样的题目,想了想,给出了自己的答案。两种方法:方法一:比较愚蠢;方法二:二分查找法。觉得麻烦直接看方法二,会好理解很多。*

1. 方法一(愚蠢的方法)

package com.study;

import java.util.ArrayList;
import java.util.Scanner;

public class testnumber {

    public static void main(String[] args) {
        ArrayList<String> num = new ArrayList<>();
        System.out.print("设置总数据量:");
        int total = new Scanner(System.in).nextInt();
        System.out.println("输入打算删除的两个数x,y");//模拟随机删除两条数据,0<x,y<=total,x!=y
        Scanner input = new Scanner(System.in);
        int x = input.nextInt();
        int y = input.nextInt();
        int[] arr = new int[total-2];
        for(int i=0;i<(total-2);i++){//此处可以设置成存一百万条数据,用于模拟从数据库过来的
            String str = "a-"+(i+1);//类似格式“AAAAOrde-0000001”
            num.add(str);
        }
        if(x > y){
            int temp = y;
            y = x;
            x = temp;
        }
        //删除指定的两个数
        num.remove(x-1);
        num.remove(y-2);
        long start = System.currentTimeMillis();

        for(int i=0;i<(total-2);i++){
            arr[i] = Integer.parseInt(num.get(i).replace("a-",""));
        }
        find(arr,0,0);
        long end = System.currentTimeMillis();
        System.out.println("消耗时间:"+(end-start)+"毫秒");
    }

    public static void find(int[] arr,int start,int flag){
            if(flag == 1){
                for(;start<arr.length;start++){
                    if(arr[start] - start == 3){
                        System.out.println("删除的编号:"+(arr[start]-1));
                        return;
                    }
                }
            }else{
                for(;start<arr.length;start++){
                    if(arr[start] - start == 3){
                        System.out.println("删除的编号:"+ (arr[start]-1)+"和"+(arr[start]-2));
                        return;
                    }else if(arr[start] - start == 2){
                        flag = 1;
                        System.out.println("删除的编号:"+(arr[start]-1));
                        find(arr,start+1,flag);
                        return;//此处一定要有return,不然还会继续执行代码
                    }
                }
            }
    }
}

运行结果:
在这里插入图片描述

2. 方法二:二分查找法

package com.study;

import java.util.ArrayList;
import java.util.Scanner;

public class testnumber {

    public static void main(String[] args) {
        ArrayList<String> num = new ArrayList<>();
        System.out.print("设置总数据量:");
        int total = new Scanner(System.in).nextInt();
        System.out.println("输入打算删除的两个数x,y");
        Scanner input = new Scanner(System.in);
        int x = input.nextInt();
        int y = input.nextInt();
        int[] arr = new int[total - 2];
        for (int i = 0; i < total; i++) {//此处可以设置成存一百万条数据,用于模拟从数据库度过来的
            String str = "a-" + (i + 1);//类似格式“AAAAOrde-0000001”
            num.add(str);
        }
        if (x > y) {
            int temp = y;
            y = x;
            x = temp;
        }
        //删除指定的两个数
        num.remove(x - 1);
        num.remove(y - 2);
        long start = System.currentTimeMillis();
        for (int i = 0; i < (total - 2); i++) {
            arr[i] = Integer.parseInt(num.get(i).replace("a-", ""));
        }
        int flag =0;//用于标记找到了几个数,当flag=2时,退出循环,已经找到两个数。可以扩展到flag个数,删除flag个整数,然后进行查找
        for(int i=1;i<=total && flag!=2;i++){
            int res = find3(arr, i, flag);
            if(res != -10){
                System.out.println("删除的数字为:"+res);
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("消耗时间:" + (end - start) + "毫秒");
    }

    public static int find3(int[] a, int i, int flag) {
        int start = 0;
        int end = a.length;
        while (start <= end) {
            int mid = (start + end) / 2;
            if (i < a[mid]) {
                end = mid - 1;
            } else if (i > a[mid]) {
                start = mid + 1;
            } else {
                return -10;//说明这个数存在
            }
        }
        flag++;
        return i;
    }
}

在这里插入图片描述
明显方法二更好理解,也更简单。这里通过一个逆向思维来使用二分查找法。原本二分查找法是用于在一个有序数组中,查找某个值,查到则返回对应数组角标;若查不到则返回-1。但是这里我们反其道而行之:题目的意思是找到缺失的两个数字,那么只需要把查不到的情况,修改成返回这个缺少值,那么就可以找到我们所需要的缺少值。从而循环一百万次,我们在这里用flag作为标志,当flag==2时,便退出for循环。这里可以推广下去,你缺少x个数字,想把这x个数字找出来,那么对应把flag修改成x即可。

发布了33 篇原创文章 · 获赞 5 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_41623154/article/details/105082605