程序员代码面试指南之笔记01(上)

简介: 一、算法数据结构基础课第一节一、 评估算法

程序员代码面试指南之笔记01

一、算法数据结构基础课

第一节

一、 评估算法优劣的核心指标是什么?

(1)时间复杂度(流程决定)

(2)额外空间复杂度(流程决定)

(3)常数项时间(实现细节决定)

二、什么是时间复杂度?时间复杂度怎么估算?

(1)常数时间的操作

(2)确定算法流程的总操作数量与样本数量之间的表达式关系

(3)只看表达式最高阶项的部分

三、 何为常数时间的操作?

如果一个操作的执行时间不以具体样本量为转移,每次执行时间都是固定时间。称这样的操作为常数时间的操作。

四、 常见的常数时间的操作

(1)常见的算术运算(+、-、*、/、% 等)

(2)常见的位运算(>>、>>>、<<、|、&、^等)

(3)赋值、比较、自增、自减操作等

(4)数组寻址操作

总之,执行时间固定的操作都是常数时间的操作。

反之,执行时间不固定的操作,都不是常数时间的操作。

五、 如何确定算法流程的总操作数量与样本数量之间的表达式关系?

1,想象该算法流程所处理的数据状况,要按照最差情况来。

2,把整个流程彻底拆分为一个个基本动作,保证每个动作都是常数时间的操作。

3,如果数据量为N,看看基本动作的数量和N是什么关系。

六、 如何确定算法流程的时间复杂度?

当完成了表达式的建立,只要把最高阶项留下即可。低阶项都去掉,高阶项的系数也去掉。

记为:O(忽略掉系数的高阶项)

七、通过三个具体的例子,来实践一把时间复杂度的估算

1、选择排序

过程:

arr[0~N-1]范围上,找到最小值所在的位置,然后把最小值交换到0位置。

arr[1~N-1]范围上,找到最小值所在的位置,然后把最小值交换到1位置。

arr[2~N-1]范围上,找到最小值所在的位置,然后把最小值交换到2位置。

arr[N-1~N-1]范围上,找到最小值位置,然后把最小值交换到N-1位置。

估算:

很明显,如果arr长度为N,每一步常数操作的数量,如等差数列一般。

所以,总的常数操作数量 = a*(N^2) + b*N + c (a、b、c都是常数)

所以选择排序时间复杂度为O(N^2)

176453 从小到大排序

每个位置上的数字都是由在这个位置之后的所有数字中选择的一个最小的数字。

【1】 1 7 6 4 5 3

【2】 1 7 6 4 5 3

【3】 1 3 6 4 5 7

【4】 1 3 4 6 5 7

【5】 1 3 4 5 6 7

第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置

然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾

以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。

//选择排序
public class Code01_SelectionSort {
  public static void selectionSort(int[] arr) {
    if (arr == null || arr.length < 2) {
      return;
    }
    // 0~n-1
    // 1~n-1
    // 2~n-1
    for (int i = 0; i < arr.length - 1; i++) { // i ~ N-1
      // 最小值在哪个位置上  i~n-1
      int minIndex = i;
      for (int j = i + 1; j < arr.length; j++) { // i ~ N-1 上找最小值的下标 
        // i ~ N-1 上找最小值的下标 
        minIndex = arr[j] < arr[minIndex] ? j : minIndex;
      }
      swap(arr, i, minIndex);
    }
  }
  public static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  // for test
  public static void comparator(int[] arr) {
    Arrays.sort(arr);
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    // Math.random()  [0,1)
    // Math.random()*N  [0,N)
      // (int)(Math.random()*N)  [0,N-1]  小数转整数
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static int[] copyArray(int[] arr) {
    if (arr == null) {
      return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
    }
    return res;
  }
  // for test
  public static boolean isEqual(int[] arr1, int[] arr2) {
    if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
    }
    if (arr1 == null && arr2 == null) {
      return true;
    }
    if (arr1.length != arr2.length) {
      return false;
    }
    for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
        return false;
      }
    }
    return true;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  // for test
  public static void main(String[] args) {
    int testTime = 500000;
    int maxSize = 100;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      selectionSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
        succeed = false;
        printArray(arr1);
        printArray(arr2);
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    int[] arr = generateRandomArray(maxSize, maxValue);
    printArray(arr);
    selectionSort(arr);
    printArray(arr);
  }
}
  }
  // 交换arr的i和j位置上的值
  private static void swap(int[] arr, int i, int j) {
    int tmp=arr[i];
    arr[i]=arr[j];
    arr[j]=tmp;
  }
}

2、冒泡排序

过程:

在arr[0~N-1]范围上:

arr[0]和arr[1],谁大谁来到1位置;arr[1]和arr[2],谁大谁来到2位置…arr[N-2]和arr[N-1],谁大谁来到N-1位置

在arr[0~N-2]范围上,重复上面的过程,但最后一步是arr[N-3]和arr[N-2],谁大谁来到N-2位置

在arr[0~N-3]范围上,重复上面的过程,但最后一步是arr[N-4]和arr[N-3],谁大谁来到N-3位置

最后在arr[0~1]范围上,重复上面的过程,但最后一步是arr[0]和arr[1],谁大谁来到1位置

估算:

很明显,如果arr长度为N,每一步常数操作的数量,依然如等差数列一般

所以,总的常数操作数量 = a*(N^2) + b*N + c (a、b、c都是常数)

所以冒泡排序时间复杂度为O(N^2)

冒泡排序是一种简单的排序算法。

它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。

走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

//冒泡排序
public class Code02_BubbleSort {
  public static void bubbleSort(int[] arr) {
    if (arr == null || arr.length < 2) {
      return;
    }
    for (int e = arr.length - 1; e > 0; e--) { // 0 ~ e
      for (int i = 0; i < e; i++) {
        if (arr[i] > arr[i + 1]) {
          swap(arr, i, i + 1);
        }
      }
    }
  }
  // 交换arr的i和j位置上的值
  public static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
  }
  // for test
  public static void comparator(int[] arr) {
    Arrays.sort(arr);
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static int[] copyArray(int[] arr) {
    if (arr == null) {
      return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
    }
    return res;
  }
  // for test
  public static boolean isEqual(int[] arr1, int[] arr2) {
    if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
    }
    if (arr1 == null && arr2 == null) {
      return true;
    }
    if (arr1.length != arr2.length) {
      return false;
    }
    for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
        return false;
      }
    }
    return true;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  // for test
  public static void main(String[] args) {    
    int testTime = 500000;
    int maxSize = 100;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      bubbleSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
        succeed = false;
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    int[] arr = generateRandomArray(maxSize, maxValue);
    printArray(arr);
    bubbleSort(arr);
    printArray(arr);
  }
}

3、插入排序

过程:

想让arr[0~0]上有序,这个范围只有一个数,当然是有序的。

想让arr[0~1]上有序,所以从arr[1]开始往前看,如果arr[1]<arr[0],就交换。否则什么也不做。

想让arr[0~i]上有序,所以从arr[i]开始往前看,arr[i]这个数不停向左移动,一直移动到左边的数字不再比自己大,停止移动。

最后一步,想让arr[0~N-1]上有序, arr[N-1]这个数不停向左移动,一直移动到左边的数字不再比自己大,停止移动。

估算时发现这个算法流程的复杂程度,会因为数据状况的不同而不同。

你发现了吗?

如果某个算法流程的复杂程度会根据数据状况的不同而不同,那么你必须要按照最差情况来估计。

很明显,在最差情况下,如果arr长度为N,插入排序的每一步常数操作的数量,还是如等差数列一般

所以,总的常数操作数量 = a*(N^2) + b*N + c (a、b、c都是常数)

所以插入排序时间复杂度为O(N^2)。

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。

每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

​​//插入排序
public class Code03_InsertionSort {
  public static void insertionSort(int[] arr) {
    if (arr == null || arr.length < 2) {
      return;
    }
    // 0~0 有序的
    // 0~i 想有序
    for (int i = 1; i < arr.length; i++) { // 0 ~ i 做到有序
      // arr[i]往前看,一直交换到合适的位置停止
      // ...(<=)  ?       <- i
      for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
        swap(arr, j, j + 1);
      }
    }
  }
  // i和j是一个位置的话,会出错
  public static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
  }
  // for test
  public static void comparator(int[] arr) {
    Arrays.sort(arr);
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    // Math.random() ->  [0,1) 所有的小数,等概率返回一个
    // Math.random() * N -> [0,N) 所有小数,等概率返回一个
    // (int)(Math.random() * N) -> [0,N-1] 所有的整数,等概率返回一个
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())]; // 长度随机 
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) 
          - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static int[] copyArray(int[] arr) {
    if (arr == null) {
      return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
    }
    return res;
  }
  // for test
  public static boolean isEqual(int[] arr1, int[] arr2) {
    if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
    }
    if (arr1 == null && arr2 == null) {
      return true;
    }
    if (arr1.length != arr2.length) {
      return false;
    }
    for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
        return false;
      }
    }
    return true;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  // for test
  public static void main(String[] args) {
    int testTime = 500000;
    int maxSize = 100; // 随机数组的长度0~100
    int maxValue = 100;// 值:-100~100
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      insertionSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
        // 打印arr1
        // 打印arr2
        succeed = false;
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    int[] arr = generateRandomArray(maxSize, maxValue);
    printArray(arr);
    insertionSort(arr);
    printArray(arr);
  }
}

注意:

1,算法的过程,和具体的语言是无关的

2,想分析一个算法流程的时间复杂度的前提,是对该流程非常熟悉

3,一定要确保在拆分算法流程时,拆分出来的所有行为都是常数时间的操作。这意味着你写算法时,对自己的用过的每一个系统api,都非常的熟悉。否则会影响你对时间复杂度的估算。

八、 时间复杂度的意义

抹掉了好多东西,只剩下了一个最高阶项啊…

那这个东西有什么意义呢?

时间复杂度的意义在于:

当我们要处理的样本量很大很大时,我们会发现低阶项是什么不是最重要的;每一项的系数是什么,不是最重要的。真正重要的就是最高阶项是什么

这就是时间复杂度的意义,它是衡量算法流程的复杂程度的一种指标,该指标只与数据量有关,与过程之外的优化无关。

九、 额外空间复杂度

你要实现一个算法流程,在实现算法流程的过程中,你需要开辟一些空间来支持你的算法流程。

作为输入参数的空间,不算额外空间。

作为输出结果的空间,也不算额外空间。

因为这些都是必要的、和现实目标有关的。所以都不算。

但除此之外,你的流程如果还需要开辟空间才能让你的流程继续下去。这部分空间就是额外空间。

如果你的流程只需要开辟有限几个变量,额外空间复杂度就是O(1)。

十、 算法流程的常数项

我们会发现,时间复杂度这个指标,是忽略低阶项和所有常数系数的。

难道同样时间复杂度的流程,在实际运行时候就一样的好吗?

当然不是。

时间复杂度只是一个很重要的指标而已。如果两个时间复杂度一样的算法,你还要去在时间上拼优劣,就进入到拼常数时间的阶段,简称拼常数项。

十一、 算法流程的常数项的比拼方式

放弃理论分析,生成随机数据直接测。

为什么不去理论分析?

不是不能纯分析,而是没必要。因为不同常数时间的操作,虽然都是固定时间,但还是有快慢之分的。

比如,位运算的常数时间原小于算术运算的常数时间,这两个运算的常数时间又远小于数组寻址的时间。

所以如果纯理论分析,往往会需要非常多的分析过程。都已经到了具体细节的程度,莫不如交给实验数据好了。

十二、 面试、比赛、刷题中,一个问题的最优解是什么意思?

一般情况下,认为解决一个问题的算法流程,在时间复杂度的指标上,一定要尽可能的低,先满足了时间复杂度最低这个指标之后,使用最少的空间的算法流程,叫这个问题的最优解

一般说起最优解都是忽略掉常数项这个因素的,因为这个因素只决定了实现层次的优化和考虑,而和怎么解决整个问题的思想无关。

十三、 常见的时间复杂度(我们陆续都会见到的)

排名从好到差:

O(1)  

O(logN)  

O(N)  

O(N*logN)  

O(N^2)   O(N^3)   …   O(N^K)

O(2^N)   O(3^N)   …   O(K^N)

O(N!)

十四、 算法和数据结构学习的大脉络

1)知道怎么算的算法

2)知道怎么试的算法

我们所有的题目讲解,对于大脉络的实践贯穿始终

十五、 认识对数器

你在网上找到了某个公司的面试题,你想了好久,感觉自己会做,但是你找不到在线测试,你好心烦..

你和朋友交流面试题,你想了好久,感觉自己会做,但是你找不到在线测试,你好心烦..

你在网上做笔试,但是前几个测试用例都过了,突然一个巨大无比数据量来了,结果你的代码报错了,如此大的数据量根本看不出哪错了,你好心烦…

1,你想要测的方法a

2,实现复杂度不好但是容易实现的方法b

3,实现一个随机样本产生器

4,把方法a和方法b跑相同的随机样本,看看得到的结果是否一样

5,如果有一个随机样本使得比对结果不一致,打印样本进行人工干预,改对方法a和方法b

6,当样本数量很多时比对测试依然正确,可以确定方法a已经正确。

public class Code01_SelectionSort {
  public static void selectionSort(int[] arr) {
    if (arr == null || arr.length < 2) {
      return;
    }
    // 0~n-1
    // 1~n-1
    // 2~n-1
    for (int i = 0; i < arr.length - 1; i++) { // i ~ N-1
      // 最小值在哪个位置上  i~n-1
      int minIndex = i;
      for (int j = i + 1; j < arr.length; j++) { // i ~ N-1 上找最小值的下标 
        minIndex = arr[j] < arr[minIndex] ? j : minIndex;
      }
      swap(arr, i, minIndex);
    }
  }
  public static void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  // for test  系统提供的自动排序,sort() 默认自动排序
  public static void comparator(int[] arr) {
    Arrays.sort(arr);
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    // Math.random()  [0,1)
    // Math.random()*N  [0,N)
      // (int)(Math.random()*N)  [0,N-1]  小数转整数
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static int[] copyArray(int[] arr) {
    if (arr == null) {
      return null;
    }
    int[] res = new int[arr.length];
    for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
    }
    return res;
  }
  // for test
  public static boolean isEqual(int[] arr1, int[] arr2) {
    if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
    }
    if (arr1 == null && arr2 == null) {
      return true;
    }
    if (arr1.length != arr2.length) {
      return false;
    }
    for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
        return false;
      }
    }
    return true;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  // for test  对数器
  public static void main(String[] args) {
    int testTime = 500000;//测试次数
    int maxSize = 100;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr1 = generateRandomArray(maxSize, maxValue);
      int[] arr2 = copyArray(arr1);
      selectionSort(arr1);
      comparator(arr2);
      if (!isEqual(arr1, arr2)) {
        succeed = false;
        printArray(arr1);
        printArray(arr2);
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    int[] arr = generateRandomArray(maxSize, maxValue);
    printArray(arr);
    selectionSort(arr);
    printArray(arr);
  }
}

十六、 认识二分法

public class Code04_BSExist {
  public static boolean exist(int[] sortedArr, int num) {
    if (sortedArr == null || sortedArr.length == 0) {
      return false;
    }
    int L = 0;
    int R = sortedArr.length - 1;
    int mid = 0;
    // L..R
    while (L < R) {
      mid = L + ((R - L) >> 1); // mid = (L + R) / 2
      if (sortedArr[mid] == num) {
        return true;
      } else if (sortedArr[mid] > num) {
        R = mid - 1;
      } else {
        L = mid + 1;
      }
    }
    return sortedArr[L] == num;
  }
}

经常见到的类型是在一个有序数组上,开展二分搜索

但有序真的是所有问题求解时使用二分的必要条件吗?

只要能正确构建左右两侧的淘汰逻辑,你就可以二分。

1) 在一个有序数组中,找某个数是否存在

2) 在一个有序数组中,找>=某个数最左侧的位置

public class Code05_BSNearLeft {
  // 在arr上,找满足>=value的最左位置
  public static int nearestIndex(int[] arr, int value) {
    int L = 0;
    int R = arr.length - 1;
    int index = -1; // 记录最左的对号
    while (L <= R) {
      int mid = L + ((R - L) >> 1);
      if (arr[mid] >= value) {
        index = mid;
        R = mid - 1;
      } else {
        L = mid + 1;
      }
    }
    return index;
  }
  // for test
  public static int test(int[] arr, int value) {
    for (int i = 0; i < arr.length; i++) {
      if (arr[i] >= value) {
        return i;
      }
    }
    return -1;
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  public static void main(String[] args) {
    int testTime = 500000;
    int maxSize = 10;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr = generateRandomArray(maxSize, maxValue);
      Arrays.sort(arr);
      int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
      if (test(arr, value) != nearestIndex(arr, value)) {
        printArray(arr);
        System.out.println(value);
        System.out.println(test(arr, value));
        System.out.println(nearestIndex(arr, value));
        succeed = false;
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
  }
}

3) 在一个有序数组中,找<=某个数最右侧的位置

public class Code05_BSNearRight {
  // 在arr上,找满足<=value的最右位置
  public static int nearestIndex(int[] arr, int value) {
    int L = 0;
    int R = arr.length - 1;
    int index = -1; // 记录最右的对号
    while (L <= R) {
      int mid = L + ((R - L) >> 1);
      if (arr[mid] <= value) {
        index = mid;
        L = mid + 1;
      } else {
        R = mid - 1;
      }
    }
    return index;
  }
  // for test
  public static int test(int[] arr, int value) {
    for (int i = arr.length - 1; i >= 0; i--) {
      if (arr[i] <= value) {
        return i;
      }
    }
    return -1;
  }
  // for test
  public static int[] generateRandomArray(int maxSize, int maxValue) {
    int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
    }
    return arr;
  }
  // for test
  public static void printArray(int[] arr) {
    if (arr == null) {
      return;
    }
    for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
    }
    System.out.println();
  }
  public static void main(String[] args) {
    int testTime = 500000;
    int maxSize = 10;
    int maxValue = 100;
    boolean succeed = true;
    for (int i = 0; i < testTime; i++) {
      int[] arr = generateRandomArray(maxSize, maxValue);
      Arrays.sort(arr);
      int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
      if (test(arr, value) != nearestIndex(arr, value)) {
        printArray(arr);
        System.out.println(value);
        System.out.println(test(arr, value));
        System.out.println(nearestIndex(arr, value));
        succeed = false;
        break;
      }
    }
    System.out.println(succeed ? "Nice!" : "Fucking fucked!");
  }
}
目录
相关文章
|
4月前
|
存储 算法 程序员
【Leetcode 程序员面试金典 01.01】判定字符是否唯一 —— 位运算|哈希表
可以使用哈希表或位运算来解决此问题:由题可知s[i]仅包含小写字母,int[26]即能表示字符的出现次数;
|
4月前
|
算法 程序员 索引
【Leetcode 程序员面试金典 02.08】 —— 环路检测 |双指针
我们可以使用双指针解决本题,由数学推导可知:a 的距离为(环长度的倍数 - b),即 tmp 指针从头节点走到环开头节点等于 slow 指针走到环开头节点的距离
|
4月前
|
Java 程序员
【Leetcode 程序员面试金典 05.01】插入 —— 位运算
位运算问题,只需要把 N 的 i 到 j 位都置 0 后再和 M 左移 i 位的结果进行按位或即可
|
4月前
|
算法 架构师 安全
10年Java面试总结:Java程序员面试必备的面试技巧
作为一名资深10年Java技术专家,我参与了无数次的面试,无论是作为面试者还是面试官。在这里,我将分享我的一些面试经历和面试技巧,希望能帮助即将面临面试的Java程序员们。回顾我的Java职业生涯,我清晰地记得一次特别的面试经历。那是我申请一家知名科技公司的Java开发岗位。为了这次面试,我花了几周的时间准备,这不仅包括Java的基础和高级知识,还有关于公司产品的研究。
150 0
|
3月前
|
运维 算法 程序员
程序员去国企:长城资产IT岗位秋招面试记录
【2月更文挑战第7天】本文介绍2024届秋招中,中国长城资产管理股份有限公司的信息技术岗岗位一面的面试基本情况、提问问题等~
|
4月前
|
安全 Java 数据库连接
啃完这些Spring知识点,我竟吊打了阿里面试官(附面经+笔记)
对于开发同学来说,Spring 框架熟悉又陌生。 熟悉:开发过程中无时无刻不在使用 Spring 的知识点;陌生:对于基本理论知识疏于整理与记忆。导致很多同学面试时对于 Spring 相关的题目知其答案,但表达不够完整准确。
|
4月前
|
存储 关系型数据库 MySQL
最全的MySQL总结,助你向阿里“开炮”(面试题+笔记+思维图)
作为一名编程人员,对MySQL一定不会陌生,尤其是互联网行业,对MySQL的使用是比较多的。对于求职者来说,MySQL又是面试中一定会问到的重点,很多人拥有大厂梦,却因为MySQL败下阵来。实际上,MySQL并不难,今天这份最全的MySQL总结,助你向阿里“开炮”,拿下offer没啥问题。
|
4月前
|
SQL 缓存 Java
程序员的30大Mybatis面试问题及答案
程序员的30大Mybatis面试问题及答案
|
2月前
|
Java 程序员
java线程池讲解面试
java线程池讲解面试
62 1
|
3月前
|
存储 关系型数据库 MySQL
2024年Java秋招面试必看的 | MySQL调优面试题
随着系统用户量的不断增加,MySQL 索引的重要性不言而喻,对于后端工程师,只有在了解索引及其优化的规则,并应用于实际工作中后,才能不断的提升系统性能,开发出高性能、高并发和高可用的系统。 今天小编首先会跟大家分享一下MySQL 索引中的各种概念,然后介绍优化索引的若干条规则,最后利用这些规则,针对面试中常考的知识点,做详细的实例分析。
253 0
2024年Java秋招面试必看的 | MySQL调优面试题

相关实验场景

更多