引言
??总结算法基本概念以及常见的算法思路。
基本概念
时间复杂度
- 在表达式中,只需要高阶项,去除低阶项和高阶项的系数,剩余部分
f(n) ,则时间复杂度为O(f(n)) 。
常数
- 常数操作:若一个操作和样本的数据量无关,每次都是固定时间内完成操作,则成为常数操作。
空间复杂度
排序算法
冒泡排序
算法
大的往后冒泡:
- 将序列中所有元素两两比较,将最大的数往后交换,冒泡到最后面。
- 将剩余序列中所有元素两两比较,将最大的数往后交换,冒泡到最后。
- 重复第2步,直到只剩下一个数。
代码
时间复杂度:O(n^2)
package com.test.selfcoding.algorithm.sort;
import com.test.selfcoding.utils.RandomArrayUtil;
import java.util.Arrays;
public class BubbleSort {
public static void bubbleSort1(int[] arr) {
int count = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
count++;
}
}
System.out.println("times: " + count);
}
public static void bubbleSort2(int[] arr) {
int count = 0;
for (int i = 0; i < arr.length - 1; i++) {
boolean flag = true;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
flag = false;
}
count++;
}
if (flag) {
break;
}
}
System.out.println("times: " + count);
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 6, 7, 8};
bubbleSort1(arr);
System.out.println(Arrays.toString(arr));
bubbleSort2(arr);
System.out.println(Arrays.toString(arr));
int[] arr1 = RandomArrayUtil.generateRandomArray(1000, 1000);
int[] arr2 = RandomArrayUtil.copyArray(arr1);
bubbleSort1(arr1);
System.out.println(Arrays.toString(arr1));
bubbleSort2(arr2);
System.out.println(Arrays.toString(arr2));
}
}
times: 36
[1, 2, 3, 4, 5, 6, 6, 7, 8]
times: 8
[1, 2, 3, 4, 5, 6, 6, 7, 8]
times: 8646
[-860, -843, -776, -760, -731, -696, -694, -694, -674, -659, -658, -655, -651, -641, -617, -604, -558, -556, -547, -544, -540, -524, -524, -519, -512, -496, -463, -439, -429, -407, -401, -362, -346, -335, -303, -291, -290, -277, -271, -267, -248, -239, -231, -228, -227, -221, -221, -219, -202, -181, -178, -153, -143, -142, -134, -113, -101, -75, -68, -50, -33, -33, -22, -16, 6, 16, 27, 36, 37, 41, 47, 57, 67, 75, 91, 96, 109, 119, 135, 146, 152, 159, 160, 175, 176, 192, 202, 211, 217, 218, 281, 281, 299, 313, 334, 354, 359, 359, 375, 377, 404, 409, 441, 445, 446, 459, 459, 472, 478, 488, 510, 514, 532, 553, 567, 580, 582, 583, 612, 635, 643, 661, 662, 680, 682, 693, 715, 742, 790, 792, 795, 814]
times: 8510
[-860, -843, -776, -760, -731, -696, -694, -694, -674, -659, -658, -655, -651, -641, -617, -604, -558, -556, -547, -544, -540, -524, -524, -519, -512, -496, -463, -439, -429, -407, -401, -362, -346, -335, -303, -291, -290, -277, -271, -267, -248, -239, -231, -228, -227, -221, -221, -219, -202, -181, -178, -153, -143, -142, -134, -113, -101, -75, -68, -50, -33, -33, -22, -16, 6, 16, 27, 36, 37, 41, 47, 57, 67, 75, 91, 96, 109, 119, 135, 146, 152, 159, 160, 175, 176, 192, 202, 211, 217, 218, 281, 281, 299, 313, 334, 354, 359, 359, 375, 377, 404, 409, 441, 445, 446, 459, 459, 472, 478, 488, 510, 514, 532, 553, 567, 580, 582, 583, 612, 635, 643, 661, 662, 680, 682, 693, 715, 742, 790, 792, 795, 814]
选择排序
算法
- 第一层循环先定义一个记录最小元素的下标,然后第二层循环一次后面的数组,找到最小的元素,最后将它放到前面排序好的序列。
代码
时间复杂度:O(n^2) ,空间复杂度:O(1)
package com.test.selfcoding.algorithm;
import java.util.Arrays;
public class SelectionSort {
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;
}
if (minIndex != i) {
swap(arr, i, minIndex);
}
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = {1,5,3,7,8,4,2,1,2,6};
selectionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
插入排序
算法
- 将第一个数和第二个数排序,构成一个有序序列;
- 将后面第三个数插入进去,构成一个新的有序序列;
- 依次对第四个数、第五个数……直到最后一个数,重复第二步。
代码
时间复杂度:O(n^2) ,空间复杂度:O(1)
package com.test.selfcoding.algorithm;
import java.util.Arrays;
public class InsertionSort {
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);
}
}
}
private static void swap(int[] arr, int j, int i) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {1, 2, 5, 3, 4, 2, 7, 6, 9, 8};
insertionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
二分查找法
算法
常见应用
- 在一个有序数组中,找某个数是否存在。
- 在一个有序数组中,找大于等于某个数最左侧的位置。
- 局部最小值问题。(此处就不一定是有序, 找中间数,若是局部最小值,则返回,若不是,左侧相邻的数和右侧相邻的数谁小,则二分到此区间必定有局部最小)
代码
时间复杂度:O(logN)
异或运算
算法
a ^ 0 == a
a ^ a == 0
满足交换律和结合律。
常见应用
- 不用额外的变量交换两个数。
- 一个数组中有1个数出现了奇数次,其他数都出现偶数次,查找这1个数。
- 一个数组中有2个数出现了奇数次,其他数都出现偶数次,查找这2个数。
算法应用:136. 只出现一次的数字
136. 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:
输入: [4,1,2,1,2]
输出: 4
这种题目,我们就可以使用异或的如下两个特性进行求解:
- 一个数与本身异或,结果总是为 0
- 一个数与0异或,结果总是其自身
package com.test.selfcoding.algorithm;
public class SingleNumber {
public static int singleNumber(int[] nums) {
int ans = nums[0];
for (int i = 1; i < nums.length; i++) {
ans = ans ^ nums[i];
}
return ans;
}
public static void main(String[] args) {
int[] nums = {4,1,2,1,2};
System.out.println(singleNumber(nums));
}
}
算法应用:389.找不同
389. 找不同
package com.test.selfcoding.algorithm;
public class FindTheDifference {
public static char findTheDifferenceWithXOR(String s, String t) {
int ans = 0;
for (int i = 0; i < s.length(); i++) {
ans ^= s.charAt(i);
}
for (int j = 0; j < t.length(); j++) {
ans ^= t.charAt(j);
}
return (char)ans;
}
public static char findTheDifferenceWithCount(String s, String t) {
int[] letter = new int[26];
for (int i = 0; i < s.length(); i++) {
char sChar = s.charAt(i);
letter[sChar - 'a']++;
}
for (int j = 0; j < t.length(); j++) {
char tChar = t.charAt(j);
letter[tChar - 'a']--;
if (letter[tChar - 'a'] < 0) {
return tChar;
}
}
return ' ';
}
public static char findTheDifferenceWithASCII(String s, String t) {
int asciiS = 0, asciiT = 0;
for (int i = 0; i < s.length(); i++) {
asciiS += s.charAt(i);
}
for (int j = 0; j < t.length(); j++) {
asciiT += t.charAt(j);
}
return (char) (asciiT - asciiS);
}
public static void main(String[] args) {
String s = "abcdef";
String t = "abcdfeg";
System.out.println(findTheDifferenceWithXOR(s, t));
System.out.println(findTheDifferenceWithCount(s, t));
System.out.println(findTheDifferenceWithASCII(s, t));
}
}
算法应用:寻找2个奇数次的数
package com.test.selfcoding.algorithm;
import java.util.Arrays;
public class Find2OddNumbers {
public static int[] find2OddNumbers(int[] arr) {
int eor = 0;
for (int cur : arr) {
eor ^= cur;
}
int right = eor & (~eor + 1);
int onlyOne = 0;
for (int cur : arr) {
if ((cur & right) == 1) {
onlyOne ^= cur;
}
}
return new int[] {onlyOne, eor ^ onlyOne} ;
}
public static void main(String[] args) {
int[] arr = new int[] {1, 2, 3, 4, 2, 1, 3, 5, 4, 6, 7, 7};
System.out.println(Arrays.toString(find2OddNumbers(arr)));
}
}
对数器
package com.test.selfcoding.algorithm;
import java.util.Arrays;
public class SelectionSort {
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;
}
if (minIndex != i) {
swap(arr, i, minIndex);
}
}
}
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
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;
}
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;
}
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;
}
public static void sortArray(int[] arr) {
Arrays.sort(arr);
}
public static void main(String[] args) {
int testTime = 600000;
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);
sortArray(arr2);
if (!isEqual(arr1, arr2)) {
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
succeed = true;
break;
}
}
System.out.println("result: " + (succeed ? "succeeded" : "failed!"));
int[] arr = generateRandomArray(maxSize, maxValue);
System.out.println(Arrays.toString(arr));
selectionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
|