public class code01 {
/**
* 选择排序
* 遍历一轮选择最小的,每轮确定一个数的位置
* 时间复杂度O(N^2),额外空间复杂度O(1)
*/
public static void selectionSort(int[] arr) {
if (arr == null || arr.length < 2){
return;
}
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
for (int j = i + 1; j <arr.length; j++) {
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
// 如果minIndex等于i,就是其本身就不用交换,如果使用异或交换就会变为0
if (minIndex != i) {
swap(arr, i, minIndex);
}
}
}
/**
* 冒泡排序
* 遍历一轮,确定一个数的位置,相邻比较
* 时间复杂度O(N^2),额外空间复杂度O(1)
*/
public static void bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int k = arr.length - 1; k > 0; k--) {
for (int i = 0; i < k; i++) {
if (arr[i] > arr[i+1]) {
swap(arr, i, i + 1);
}
}
}
}
/**
* 插入排序
* 左边有序,右边无序
* 时间复杂度O(N^2),额外空间复杂度O(1)
*/
public static void insertionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
for (int j = i - 1; j >= 0 && arr[j] > arr[j+1]; j--) {
swap(arr, j, j+1);
}
}
}
/**
* 数组交换
*/
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];
}
/**
* 在有序数组中,使用二分法查找某数是否存在
* @return
*/
public static boolean BSExist(int[] arr, int num) {
if (arr == null && arr.length == 0) {
return false;
}
int left = 0;
int right = arr.length -1;
int mid = 0;
while (left < right) {
// mid = left + ((right - left) >> 1);
mid = (left + right) / 2;
if (arr[mid] == num) {
return true;
} else if (arr[mid] > num) {
right = mid -1;
} else {
left = mid + 1;
}
}
// return sortedArr[left] == num;
return false;
}
/**
* 在有序数组中,使用二分查找>=某个数的最左侧位置
* @return
*/
public static int BSNearLeft(int[] arr, int num) {
if (arr == null && arr.length == 0) {
return 0;
}
int index = -1;
int left = 0;
int right = arr.length -1;
int mid;
while (left < right) {
mid = left + ((right - left) >> 1);
if (arr[mid] >= num) {
index = mid;
right = mid -1;
} else {
left = mid + 1;
}
}
return index;
}
/**
* 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数?
* 运用异或运算,出现偶数次的数异或后等于0,最后异或的结果就是出现奇数次的数
* 0^N == N
* N^N == 0
* @param arr
*/
public static void printOddTimesNum1(int[] arr) {
int a = 0;
for (int b :arr) {
a = a ^ b;
}
System.out.println(a);
}
/**
* 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
* @param arr
*/
public static void printOddTimesNum2(int[] arr) {
int a = 0;
int one = 0;
// 获取到2个数异或的值
for (int b :arr) {
a = a ^ b;
}
// 获取2个数异或的值的最右边的1,与上(取反+1)
int rightOne = a & (~a + 1);
// 将数组分为2类,独自异或,可以得到一个出现奇数次的数
for (int b :arr) {
if ((b & rightOne) != 0) {
one ^= b;
}
}
System.out.println(one +" "+ (one ^ a));
}
/**
* 用递归方法找一个数组中的最大值
* @param arr
* @param left
* @param right
* @return
*/
public static int getMax(int[] arr, int left, int right) {
if (left == right) {
return arr[left];
}
int mid = left + ((right - left) >> 1);
int leftMax = getMax(arr, left, mid);
int rightMax = getMax(arr, mid + 1, right);
return Math.max(leftMax,rightMax);
}
/**
* 局部最小值问题
* 局部最小值的概念。arr长度为1时,arr[0]是局部最小。arr的长度为N(N > 1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;
* 如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小;如果0<i<N-1,既有arr[i]<arr[i-1],又有arr[i]<arr[i+1],那么arr[i]是局部最小。
* 给定无序数组arr,已知arr中任意两个相邻的数都不相等。写一个函数,只需返回arr中任意一个局部最小出现的位置即可。
* @param arr
* @return
*/
public static int getLessIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1;
}
if (arr.length == 1 || arr[0] < arr[1]) {
return 0;
}
if (arr[arr.length - 1] < arr[arr.length - 2]) {
return arr.length -1;
}
int left = 1;
int right = arr.length - 2;
int mid = 0;
while (left < right) {
mid = left + ((right - left) >> 1);
// 注意这里判断条件
// 上升趋势,抛弃右边,保持先降后升的趋势
if (arr [mid] > arr[mid - 1]) {
right = mid - 1;
// 下降趋势,抛弃左边 保持先降后升趋势
} else if (arr[mid] > arr[mid + 1]) {
left = mid + 1;
} else {
// 找到局部最小了
return mid;
}
}
// 剩余一个
return left;
}
public static void main(String[] args) {
int[] arr1 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
// 选择排序
selectionSort(arr1);
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
int[] arr2 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
// 冒泡排序
bubbleSort(arr2);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
int[] arr3 = {212,1561,451,15415,451,12,4511,45315,5616,4565};
// 插入排序
insertionSort(arr3);
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr3[i]);
}
// 二分查找某数
boolean b = BSExist(arr3, 451);
System.out.println(b);
// 二分查找>=某数最左侧位置
int i = BSNearLeft(arr3, 452);
System.out.println(i);
// 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数
int[] arr4 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 };
printOddTimesNum1(arr4);
// 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
int[] arr5 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 };
printOddTimesNum2(arr5);
// 递归获取数组最大值
int max = getMax(arr3, 0, arr3.length - 1);
System.out.println(max);
// 局部最小值问题
int[] arr6 = {6, 5, 7, 3, 4, 6, 7, 8};
for (int j = 0; j != arr6.length; j++) {
System.out.print(arr6[j] + " ");
}
System.out.println();
int index = getLessIndex(arr6);
System.out.println("index: " + index + ", value: " + arr6[index]);
}
}