前言
目前是算法横行的时代,逻辑很重要,特出此文章做一个总结会持续更新
一、排序
swap异或算法用的前提是交换的数组的元素a和b分别在不同的内存里。如果在数组中想进行交换,一定要保证i和j不能相等。
1.1 选择排序
将第循环里的第一个元素和后面的比,谁小把谁放到前面,时间复杂度为n的平方
class SelectionSort(int[] arr){
public void selectionSort(int[] arr){
//排除杂条件
if(arr == null || arr.length < 2){
return;
}
for (int i = 0; i < arr.length; i++){
//外层循环的每一个i先设置为此循环的最小值的索引,给到内层循环进行比较
minIndex = i;
for (int j = i+1; j<arr.length;j++){
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
//每次一个大循环找到一个该轮最小值放到第一个
swap(arr,i,minIndex)
}
}
public void swap(int[] arr;int i;int minIndex){
int tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
1.2 冒泡排序
选择排序是将最小的放到第一位,而冒泡排序是将最大的放到最后一位,并且每次都是相邻两个在比。
class Solution {
public int[] sortArray(int[] nums) {
bubbleSort(nums);
return nums;
}
public void bubbleSort(int[] arr){
if(arr == null || arr.length < 2){
return;
}
for(int i = 0;i<arr.length;i++){
for(int j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
swap(arr,j,j+1);
}
}}}
public void swap(int[] arr,int i,int j){
//异或还可以理解为无进位相加,下面方法的使用前提是arr[i]指向的内存和arr[j]指向的内存是两块不同的内存,因为同样的内存异或会成为0
int tmp = arr[i] ;
arr[i] = arr[j];
arr[j] = tmp;
}
}
1.3 插入排序
按照算法可能情况的最差估计时间复杂度为n的平方,每次循环都保证0-n的地方是有序排序的,而且每次都是先跟前一位比,不行了才会进行互换,否则不互换,这样他最好的实现状况是时间复杂度为n。
class InsertionSort(){
public insertSort(int[] arr){
//排除杂条件
if(arr == null || arr.length < 2){
return;
}
//i从1开始是因为0-0上已经实现了排序
for (int i = 1; i < arr.length; i++){//0到i做到有序,此时已经做到了0~i-1上的数有序,所以现在比较i-1(j)和第i位置的数的大小,换到不比左边位置的数小了就停止
for(int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--){
swap(arr, j, j + 1);
}
}
}
public void swap(int[] arr,int i,int j){
//异或还可以理解为无进位相加,下面方法的使用前提是arr[i]指向的内存和arr[j]指向的内存是两块不同的内存,因为同样的内存异或会成为0
arr[i] = arr[i] ^ arr[j];
arr[j] = arr[i] ^ arr[j];
arr[i] = arr[i] ^ arr[j];
}
}
1.4 归并排序
左边排好序右边也排好序,复杂度为N*logN
public class MergeSort{
public static void process(int[] arr, int L,int R){
if(L==R){
return;
}
int mid = L+((R-L)>>1);
//先两边有序,后归并merge
process(arr,L,mid);
process(arr,mid,R);
merge(arr,L,mid,R);
}
public static void merge(int[] arr,int L,int M,int R){
//新设置一个数组放比较值
int[] help = new int[R-L+1];
int i = 0;
int p1 = L;
int p2 = M + 1;
// 哪个小放哪个,并移动相应的指针
while (p1 <= M && p2 <= R){
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]
}
//下面两个循环只会走一个
while (p1<=M){
help[i++] = arr[p1++];
}
while (p2<=R){
help[i++] = arr[p2++];
}
for(i = 0,i < help.length;i++){
//拷贝回原来数组
arr[L+i] = help[i]
}
}
}
1.5 快速排序
class Solution {
public void swap(int[] nums,int L,int R){
int tmp = nums[L];
nums[L] = nums[R];
nums[R] = tmp;
}
public int[] sortArray(int[] nums) {
int L = 0,R = nums.length-1;
quickSort(nums,L,R);
return nums;
}
public void quickSort(int[] nums,int L,int R){
if(L<R){//递归终止条件
swap(nums,L+(int)(Math.random()*(R-L+1)),R);//找随机一个数字和最后一个元素互换,记住加一
int[] middleIndex = partiton(nums,L,R);//进行分区,返回的是等于区的左索引坐标和右索引index
quickSort(nums,L,middleIndex[0]-1);//减一是因为小于区的最右边界处是等于区最左边界减一
quickSort(nums,middleIndex[1]+1,R);//加一是因为大于区最左边界是等于区最右边界加一
}
}
public int[] partiton(int[] nums,int L,int R){//L相当于此时的第三个指针
int less = L-1;//减一是因为小于区的起始索引还没有比较,所以先将小于区的指针指向第一个索引的前面一个,不能改成L+1,这样就默认第一个数字确实比被比较的数字小了,万一没有一个就会出错
int more = R;//这里R不减一是因为最后一个是被比较数字,所以开始的大于区的指针是在他前面的
while(L<more){
if(nums[L]<nums[R]){//L代表现在这一段的比较数字的指针
swap(nums,++less,L++);
}else if(nums[L]>nums[R]){
swap(nums,--more,L);//指针不前移,因为此时大于区的左边界换过来的数据还没有进行比较
}else{
L++;
}
}
swap(nums,more,R);
return new int[]{less+1,more};//返回的more没有加1是因为最后进行了交换,也就是上一行代码,此时more指向的是等于区的最后一个元素,把最后一个元素交换过来的就是被比较数字
}
}
二、查找
2.1 二分查找(有序数组找某个数是否存在)
时间复杂度为log2N
三、寻找最大数字
寻找某一个数组里的某一段区间的最大值
public class GetMax{
public static int process(int[] arr, int L,int R){
if(L==R){
return arr[L];
}
int mid = ((R-L)>>1);//寻找到中点
//递归调用
int leftMax = process(arr,L,mid);
int rightMax = process(arr,mid+1,R);
return Math.max(leftMax,rightMax);
}
}
四、两数之和
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = 0; i < nums.length; i++) {
if(map.containsKey(target - nums[i])) {
return new int[] {map.get(target-nums[i]),i};
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
}