一、简介
- 内容根据尚硅谷、黑马的视频和漫画算法书本整理收集,所以一些文字或者图片出自这些,一些是根据自己的理解写的。
- 在学习算法,仅是按文章或者书本说的可能有点难理解,毕竟是学习数据结构和算法,一些逻辑会比较复杂,甚至需要数学功底,所以最好的方法是结合视频、书、文章一起来学习,如果这个视频的老师说起来听的不太懂的话,那么就找另一个老师的视频看下,如果视频的不太懂,那么就看下书本说的,看那个更易懂一些。然后不同老师/作者说的算法实现方式也不一样,我们也能学到他们不同的算法思想。
- 尚硅谷、黑马视频算是对新手比较简单能理解的,还有漫画算法的书也是比较适合新手,因此推荐一起看。
参考: 1、【尚硅谷】数据结构与算法(Java数据结构与算法) https://www.bilibili.com/video/BV1E4411H73v/?spm_id_from=333.999.0.0&vd_source=548b27fee009b7ca3bfb319772b8d3e7
2、黑马程序员Java数据结构与java算法全套教程,数据结构+算法教程全资 https://www.bilibili.com/video/BV1iJ411E7xW/?spm_id_from=333.999.0.0&vd_source=548b27fee009b7ca3bfb319772b8d3e7
3、【程序员小灰】漫画算法:小灰的算法之旅(全彩)(博文视点出品) https://item.jd.com/12513751.html
二、数据结构和算法一些概念
数据结构:是计算机存储、组织数据的方式。可以把它看成是用来如何存数据的
算法:指如何解决一类问题的明确规范。可以理解为解题的一种方式,解题的步骤。
时间复杂度:用来描述执行当前算法所消耗的时间。
空间复杂度:用来描述执行当前算法需要占用多少内存空间
三、排序算法
排序的分类:
- 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。
- 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。
常用排序算法对比:
相关术语解释
-
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面; -
不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面; -
内排序:所有排序操作都在内存中完成; -
外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行; -
时间复杂度: 一个算法执行所耗费的时间。 -
空间复杂度:运行完一个程序所需内存的大小。 -
n: 数据规模 -
k: “桶”的个数 -
In-place: 不占用额外内存 -
Out-place: 占用额外内存
简单排序和高级排序:由于简单排序时间复杂度相对要大,简单排序一般在处理大量数据或者某种特殊情况下没有高级排序效率高,因此使用场景一般适合少量的数据。
1、冒泡排序(简单排序)
冒泡排序:简单理解为前一个数和后一个数比较交互,一直从0到最后一个位置。这样的一层层比较交互就想冒泡一样。
时间复杂度:O(N^2)
冒泡排序原理:
- 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
- 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大
值。
冒泡实现方式一
图解:
java代码实现:
public class BobbleSort {
public static void main(String[] args) {
BobbleSort bobbleSort = new BobbleSort();
int[] a = {5, 8, 6, 3, 9, 2, 1, 7};
bobbleSort.bobbleSort1(a);
int[] b = {5, 8, 6, 3, 9, 2, 1, 7};
bobbleSort.bobbleSort2(b);
bobbleSort.bobbleSort3(new int[]{3,4,2,1,5,6,7,8});
}
public void bobbleSort1(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
System.out.println("一、简单冒泡排序");
System.out.println("原始数据:" + Arrays.toString(arr));
for (int i = 0; i < arr.length -1; i++) {
for (int j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
System.out.println(Arrays.toString(arr));
}
}
public void bobbleSort2(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
System.out.println("二、冒泡排序优化");
System.out.println("原始数据:" + Arrays.toString(arr));
for (int i = 0; i < arr.length -1; i++) {
boolean isSorted = true;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isSorted = false;
}
}
if (isSorted) {
break;
}
System.out.println(Arrays.toString(arr));
}
}
public void bobbleSort3(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
System.out.println("三、冒泡排序最终版");
System.out.println("原始数据:" + Arrays.toString(arr));
int lastExchangeIndex = 0;
int sotBorder = arr.length -1;
for (int i = 0; i < arr.length - 1; i++) {
boolean isSorted = true;
for (int j = 0; j < sotBorder; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isSorted = false;
lastExchangeIndex = j;
}
}
sotBorder = lastExchangeIndex;
System.out.println(Arrays.toString(arr));
if (isSorted) {
break;
}
}
}
}
冒泡实现方式二
java代码实现:
public class BobbleSort2 {
public void bobbleSort2(int[] arr){
for (int i = arr.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
2、选择排序(简单排序)
选择排序:每次遍历,选择后面没排序的数组中最小的值和没排序数组中的第一个索引值交互。
时间复杂度:O(N^2)
和冒泡排序比较: 选择排序先将前面部分就行排序,而冒泡是先将后部分进行排序。 选择排序一次循环只交互一次数据,因此比冒泡大大减少。
java代码实现:
public class SelectionSort {
public static void main(String[] args) {
SelectionSort selectionSort = new SelectionSort();
int[] a = {5, 8, 6, 3, 9, 2, 1, 7};
selectionSort.selectSort(a);
}
public void selectSort(int[] arr){
if (arr == null || arr.length == 0) {
return;
}
for (int i = 0; i < arr.length; i++) {
int min = arr[i];
int minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
System.out.println("交换后"+ Arrays.toString(arr));
}
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
}
}
3、快速排序(高级排序)
快速排序:是对冒泡排序的一种改进,类似二分查找的思想,设定一个分界值,通过该分界值将数组分成左右两部分,左部分比分界值小,右部分比分界值大。然后又通过次方法将左边和右边设定一个分界值。通过递归重复上述步骤。
时间复杂度:最坏O(n^2),最优O(nlogn),平均O(nlogn);
实现方式:
- 双边循环法:设置分界值,用两个下标指针,进行遍历比较交换,约定左边比分界值小,右边比分界值大。
- 单边循环法:设置分界值,只用一个下标指针mark,进行遍历比较交换,约定mark指针左边数据比分界值小,右边数据比分界值大。
选择排序:双边循环法
参考:https://www.bilibili.com/video/BV1E4411H73v?p=67&vd_source=548b27fee009b7ca3bfb319772b8d3e7
选择排序-双边循环法原理:
- 设置中间值为分界值。
- 循环,分界值左边设置左下标,从左往右找出比分界值大的值;右边设置右下标,从右往左找出比分界值小的,然后将这两个值进行交换(可能会将分界值和左边或者右边的数交换,这时候左下标或者右下标会超过之前的分界值,但左下标不会大于右下标)。循环后,分界值左边数据全部是小于分界值的,分界值右边数据则全部大于分界值的。
- 再向左递归,从左边部分中间设置分界值,按上述步骤;向右递归,从右边部分中间设置分界值,按上述步骤。
整体图解
分步图解:
选择排序:单边循环法
选择排序-单边循环法原理: 单边循环(使用一个mark下标,遍历后面的数据和设置基准值作比较)。具体看下面图解
单边循环法图解:
选择排序双边和单边循环java代码:
public class QuickSort {
public static void main(String[] args) {
QuickSort quitSort = new QuickSort();
System.out.println("====快速排序-双边循环====");
int[] a = {4,0,6,5,3,8,2,1};
System.out.println("原数据:"+Arrays.toString(a));
quitSort.quickSort1(a,0,a.length - 1);
System.out.println("\n\n");
System.out.println("====快速排序-单边循环====");
int[] b = {4,0,6,5,3,8,2,1};
System.out.println("原数据:"+Arrays.toString(b));
quitSort.quickSort2(b,0,b.length - 1);
}
public void quickSort1(int[] arr,int left , int right){
int l = left;
int r = right;
int pivot = arr[( right + left ) / 2];
int temp = 0;
while (l < r) {
while (arr[l] < pivot) {
l += 1;
}
while (arr[r] > pivot) {
r -= 1;
}
if (l >= r) {
break;
}
System.out.println("交换{l:"+l +",r:"+r+",arr[l]:"+arr[l]+"," +arr[r]+"}");
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
System.out.println("交换后:" + Arrays.toString(arr));
if (arr[l] == pivot) {
r -= 1;
}
if (arr[r] == pivot) {
l += 1;
}
}
System.out.println("分治后数组:" + Arrays.toString(arr));
if (l == r) {
l += 1;
r -= 1;
}
if (left < r) {
System.out.println("===向左递归===");
quickSort1(arr, left , r);
}
if (right > l) {
System.out.println("===向右递归===");
quickSort1(arr, l , right);
}
}
public void quickSort2(int[] arr,int startIndex,int endIndex){
if (startIndex >= endIndex) {
return;
}
int pivotIndex = partition(arr,startIndex,endIndex);
System.out.println("得到基准元素位置:"+Arrays.toString(arr)+",startIndex:"+startIndex+",endIndex:"+endIndex+",pivotIndex:"+pivotIndex);
System.out.println("==向左递归==");
quickSort2(arr,startIndex,pivotIndex - 1);
System.out.println("==向右递归==");
quickSort2(arr,pivotIndex + 1,endIndex);
}
public int partition(int[] arr,int startIndex,int endIndex) {
int pivot = arr[startIndex];
int mark = startIndex;
for (int i = startIndex +1; i <= endIndex; i++) {
if (arr[i] < pivot) {
mark++;
int temp = arr[mark];
arr[mark] = arr[i];
arr[i] = temp;
System.out.println("交换{mark:"+temp +",i:" + arr[mark]+"}");
}
System.out.println("数组:"+Arrays.toString(arr)+",mark:"+mark+ ", i:" +i );
}
arr[startIndex] = arr[mark];
arr[mark] = pivot;
return mark;
}
}
4、插入排序 (简单排序)
插入排序(Insertion sort)是一种简单直观且稳定的排序算法。
时间复杂度:O(N^2)
插入排序原理:
- 将所有数据分为两组,左边是排序了的,右边是未排序的。
- 找到未排序的组中的第一个元素,向左遍历比较和已排序组中的数,如果比某个数小,则在某个数前插入该数(实际和冒泡一样差不多向前交换)。插入后。
java代码实现:
public class InsertSort {
public static void main(String[] args) {
InsertSort insertSort = new InsertSort();
int[] arr = {5, 8, 6, 3, 9, 2, 1, 7};
System.out.println("原始数据:"+ Arrays.toString(arr));
insertSort.insertSort(arr);
}
public void insertSort(int[] arr){
for (int i = 0; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j - 1] > arr[j]) {
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
} else {
break;
}
}
System.out.println("未排序组第一个元素向前比较交换后的数组:"+Arrays.toString(arr)+",i:"+i);
}
System.out.println("排序后:"+ Arrays.toString(arr));
}
}
5、希尔排序(高级排序)
希尔排序是插入排序的一种,又称“缩小增量排序”,是插入排序算法的一种更高效的改进版本。
时间复杂度:O(nlogn),比插入排序快很多倍
希尔排序原理: 1.选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组(按照增长量间隔到第几个数为一组); 2.对分好组的每一组数据完成插入排序; 3.减小增长量,最小减为1,重复第二步操作
增长量h的确定:增长量h的值每一固定的规则,我们这里采用以下规则
int h=1 while(h<5){ h=2h+1;//3,7 }//循环结束后我们就可以确定h的最大值; h的减小规则为: h=h/2
希尔排序图解: 注意:当h=5时,9和间隔的第5个元素4为一组,1和间隔的第5个元素8为一组,以此类推,根据增长量间隔分组。 待插入元素:根据增长量h为待插元素,例如当h=5时,9和4为一组,那么4为待插元素,1和8位一组,那么8为待插元素,以此类推。 分组排序:待插元素和组中的元素比较交换。
java代码实现:
public class ShellSort {
public static void main(String[] args) {
ShellSort shellSort = new ShellSort();
System.out.println("=======希尔排序-交换法======");
int[] arr = {5, 8, 6, 3, 9, 2, 1, 7};
System.out.println("原始数据:"+ Arrays.toString(arr));
shellSort.shellSort(arr);
System.out.println("希尔排序-交换法排序后:"+ Arrays.toString(arr));
System.out.println("\n\n");
System.out.println("=======希尔排序-移位法======");
int[] arr2 = {5, 8, 6, 3, 9, 2, 1, 7};
System.out.println("原始数据:"+ Arrays.toString(arr2));
shellSort.shellSort2(arr2);
System.out.println("希尔排序-移位法排序后:"+ Arrays.toString(arr2));
}
public void shellSort(int[] arr){
int h = 1;
while (h < arr.length/2) {
h = 2*h + 1;
}
while (h >= 1) {
System.out.println("增长量h:" +h);
for (int i = h; i < arr.length; i++) {
for (int j = i; j >= h; j-=h) {
if (arr[j-h] > arr[j]) {
int temp = arr[j];
arr[j] = arr[j-h];
arr[j-h] = temp;
} else {
break;
}
}
System.out.println("每组待插入元素插入排序后:" + Arrays.toString(arr));
}
h = h/2;
}
}
public void shellSort2(int[] arr){
int h = 1;
while (h < arr.length / 2) {
h = 2 * h +1;
}
while (h >= 1) {
System.out.println("增长量h:" +h);
for (int i = h; i < arr.length; i++) {
int j = i;
int temp = arr[j];
if (arr[j] < arr[j-h]){
while (j - h >= 0 && temp < arr[j-h]) {
arr[j] = arr[j - h];
j -=h;
}
arr[j] = temp;
}
System.out.println("每组待插入元素插入排序后:" + Arrays.toString(arr));
}
h = h/2;
}
}
}
6、 归并排序(高级排序)
递归:定义方法时,在方法内部调用方法本身,称之为递归。
归并排序:是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序 表,称为二路归并。
时间复制度:O(nlogn)
归并排序的缺点:需要申请额外的数组空间,导致空间复杂度提升,是典型的以空间换时间的操作。
归并排序原理:
- 每次将数据拆分为尽可能元素个数相等的两组数,命名这两组数为子组,那两个子组继续按元素个数相等的拆分4个子组,按照这个规律,直到拆分为每一组只有一个数据。
- 然后将拆分后相邻的两个子组进行排序合并(归并),继续往上排序合并直到变为原来的一组数据。
排序合并原理:
- 创建一个空的辅助assist数组,两个子组A和B分别创建一个下标指针p1、p2,默认为子组A和子组B的第一个数下标,assist数组创建一个下标指针i,从子组A的p1和子组B的p2指针的数据进行比较,如果p1的数比p2小的话,则将p1的数放到assist数组的指针i处,然后子组A的p1指针加1向后移动一位,assist指针i加1,向后移动一位,否则p2比p1小,就是p2的数放到assist数组的指针i处,然后p2加1向后移动一位。继续遍历子组A和B的指针的数对比,当子组A下标p1走到A的结束位置,但子组B下标p2还没走到结束位置,这时候将子组B下标的数和剩下未走完的数按顺序放到assist数组后面,因为子组A和B都是排序的数组,A和B比较,A走完了,B剩下的数肯定是大于A的数了。如果是子组B下标走到B的结束位置,则和相反,和当子组A下标p1走到A的结束位置类推。
- 走完上述步骤后,子组A和子组B的数据合并在assist数组中了,这时候将assist数组合并的数据,复制代替原始数组的A和B数组下标的位置。
简单来说就是先拆后合
整体原理图解:
归并(合并时)原理
java代码实现:
public class MergeSort {
private int[] assist;
public static void main(String[] args) {
MergeSort mergeSort = new MergeSort();
int[] a = {5, 8, 6, 3, 9, 2, 1, 7};
System.out.println("原始数组:"+ Arrays.toString(a));
mergeSort.mergeSort(a);
System.out.println("归并排序后数组:"+ Arrays.toString(a));
}
public void mergeSort(int[] arr){
if (arr == null || arr.length == 0) {
return;
}
assist = new int[arr.length];
sort(arr,0,arr.length -1);
}
public void sort(int[] arr,int start,int end){
if (start >= end) {
return;
}
int mid = start + (end - start) / 2;
sort(arr,start,mid);
sort(arr,mid + 1, end);
merge(arr,start,mid,end);
}
public void merge(int[] arr,int start,int mid,int end) {
printMergeBefore(arr,start,mid,end);
int i = start;
int p1 = start;
int p2 = mid +1;
while (p1 <= mid && p2 <= end) {
if (arr[p1] < arr[p2]) {
assist[i++] = arr[p1++];
} else {
assist[i++] = arr[p2++];
}
}
while (p1 <= mid) {
assist[i++] = arr[p1++];
}
while (p2 <= end) {
assist[i++] = arr[p2++];
}
for (int j = start; j <= end; j++) {
arr[j] = assist[j];
}
printMergeAfter(arr,start,mid,end);
}
public void printMergeBefore(int[] arr,int start,int mid,int end){
StringBuffer aStr = new StringBuffer("左边组:[");
for (int i = start; i <= mid; i++) {
if (i > start) {
aStr.append(",");
}
aStr.append(arr[i] + "");
}
aStr.append("]");
aStr.append(" 右边组:[");
for (int i = mid + 1; i <= end; i++) {
if (i > mid + 1) {
aStr.append(",");
}
aStr.append(arr[i] + "");
}
aStr.append("]");
System.out.println("归并前的数组:" + aStr.toString() +" start:"+start+",mid:"+mid+",end:"+end);
}
private void printMergeAfter(int[] arr,int start,int mid,int end){
int[] printArr = new int[arr.length];
System.arraycopy(arr,start,printArr,start,end - start +1);
System.out.println("将两个数组归并后:"+Arrays.toString(printArr));
}
}
7、基数排序(高级排序)
基数排序:基数排序(Radix Sort)是桶排序的扩展,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用。
时间复杂度:O(n + K),k:桶的个数
基数排序原理:
- 创建10个桶,每个桶的内容是装数组,由于数字都是0到9的数,因此需要10个桶,10个桶对应的下标为0到9;
- 第一步遍历原始数组,先计算数组的每个数的个位数是什么,根据每个数的个位数和10个桶对应的下标,将数放到对应的桶中,例如542的个位数是2,那么将542放到下标为2的桶里面。依次类推,直到数组所有的数都放到桶里面。
- 第二步,再将桶里装的数组,从下标0到9的顺序把桶里数据取出来,依次放回到数组中,这时候数组就按个位数实现了排序。
- 依次类推,从上面第一步开始,不过这时候计算的是数组中每个数的10位数是什么了,然后按10位数的数字放到对应的桶中,再从桶放回数据,由于之前已经按个位数排序过,不难发现,这时候数组已经按个位和10位数排序了。
- 就这样按着数组中最大的数的位数,进行上面一轮轮放入桶再从桶中顺序拿出来,最终实现了数组的排序。
基数排序图解:
java代码实现:
public class RadixSort {
public static void main(String[] args) {
RadixSort radixSort = new RadixSort();
int[] arr = { 53, 3, 542, 748, 14, 214, 64, 46};
System.out.println("基数排序前 " + Arrays.toString(arr));
radixSort.radixSort(arr);
System.out.println("基数排序后 " + Arrays.toString(arr));
}
public void radixSort(int [] arr){
int maxVal = arr[0];
for (int i = 0; i < arr.length; i++) {
if (maxVal < arr[i]) {
maxVal = arr[i];
}
}
int maxLen = (maxVal + "").length();
int[][] bucket = new int[10][arr.length];
int[] bucketElementCounts = new int[10];
for (int i = 0,n = 1; i < maxLen; i++,n *= 10) {
for (int j = 0; j < arr.length; j++) {
int bucketIndex = arr[j] / n % 10;
bucket[bucketIndex][bucketElementCounts[bucketIndex]] = arr[j];
bucketElementCounts[bucketIndex]++;
}
int index = 0;
for (int j = 0; j < bucketElementCounts.length; j++) {
if (bucketElementCounts[j] == 0) {
continue;
}
for (int k = 0; k < bucketElementCounts[j]; k++) {
arr[index++] = bucket[j][k];
}
bucketElementCounts[j] = 0;
}
}
}
}
四、查找算法
1、二分查找(折半查找)
二分查找:数据必须有序,也叫折半查找,一种效率较高的查找方法。
二分查找原理:
- 首先确定该数组的中间下标 mid = (left + right) / 2,left为数组最左边下标,right为数组最右边下标。
- 然后让需要查找的数findVal和arr[mid]比较
- 如果findVal > arr[mid],说明你要查找的数在mid的右边,因此需要递归的向右查找
- 如果findVal < arr[mid],说明你要查找的数在mid的左边,因此需要递归的向左查找。
- findVal == arr[mid]说明找到,就返回
什么时候我们需要结束递归
- 找到就结束递归
- 递归完整个数组,仍然没有找到findVal,也需要结束递归,当left>right就需要退出。
二分查找图解:
java代码实现:
public class BinarySearch {
public static void main(String[] args) {
BinarySearch binarySearch = new BinarySearch();
int[] arr = {10, 15, 16, 17, 20 , 20, 21, 26, 90};
System.out.println("二分查找数组:"+ Arrays.toString(arr));
int result = binarySearch.binarySearch(arr,0,arr.length -1,20);
System.out.println("二分查找-递归方式结果:" + result);
System.out.println("\n\n");
int result2 = binarySearch.binarySearch2(arr,0,arr.length -1,20);
System.out.println("二分查找-普通方式结果:" + result2);
List<Integer> resultList = binarySearch.binarySearch3(arr,0,arr.length -1,20);
System.out.println("二分查找-递归方式优化结果:" + resultList);
}
public int binarySearch(int[] arr,int left,int right,int findVal) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
int midVal = arr[mid];
System.out.println("每次查找{ left:"+left+",right:"+right+",mid:"+mid+",midVal:"+midVal);
if (findVal < midVal) {
return binarySearch(arr,left,mid -1,findVal);
} else if (findVal > midVal) {
return binarySearch(arr,mid + 1,right,findVal);
} else {
return mid;
}
}
public int binarySearch2(int[] arr,int left,int right,int findVal){
int mid;
while (left <= right) {
mid = (left + right)/2;
System.out.println("每次查找{ left:"+left+",right:"+right+",mid:"+mid+",midVal:"+arr[mid]);
if (arr[mid] == findVal) {
return mid;
} else if (findVal < arr[mid] ) {
right = mid - 1;
} else if (findVal > arr[mid]) {
left = mid + 1;
}
}
return -1;
}
public List<Integer> binarySearch3(int[] arr,int left,int right,int findVal) {
if (left > right) {
return new ArrayList<Integer>();
}
int mid = (left + right) / 2;
int midVal = arr[mid];
System.out.println("每次查找{ left:"+left+",right:"+right+",mid:"+mid+",midVal:"+midVal);
if (findVal < midVal) {
return binarySearch3(arr,left,mid -1,findVal);
} else if (findVal > midVal) {
return binarySearch3(arr,mid + 1,right,findVal);
} else {
List<Integer> resIndexlist = new ArrayList<Integer>();
int temp = mid - 1;
while(true) {
if (temp < 0 || arr[temp] != findVal) {
break;
}
resIndexlist.add(temp);
temp -= 1;
}
resIndexlist.add(mid);
temp = mid + 1;
while(true) {
if (temp > arr.length - 1 || arr[temp] != findVal) {
break;
}
resIndexlist.add(temp);
temp += 1;
}
return resIndexlist;
}
}
}
|