左神-算法与数据结构基础到高级bilibili-个人笔记Java

B站链接:一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解_哔哩哔哩_bilibili本套教程由马士兵教育-左程云老师耗时100天重磅打造,适合所有想进大厂的学员收藏只是白嫖,三连才是真情!领取视频资料加小助理WX:javataozi888https://www.bilibili.com/video/BV13g41157hK?p=1

前言:1、只记录我在该视频中新学会的知识,而非视频的全部内容。2、本文插入的未标注的代码默认是视频中出现的,但有的是我自己写的,会在对应位置标注(Wen_JunRen)。3、错漏之处还请指正。

目录

主线

一、复杂度和排序算法

二、链表

三、二叉树

四、图

五、前缀树和贪心算法

小操作



主线

一、复杂度和排序算法

  1. 选择排序

    1. 思想:每一趟选出当前未排序部分中的最小值放在未排序区域的首位
    2. public static void selectionSort(int[] arr) {
      	if (arr == null || arr.length < 2) {
      		return;
      	}
      	for (int i = 0; i < arr.length - 1; i++) { // 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);
      	}
      }
  2. 冒泡排序

    1. 思想:每次都从数组首位置出发,两两比较交换相邻元素,最终一趟比较中选出一个最大值。
    2.  改进:当本次循环未发生交换时,说明排序已完成,可提前终止循环。
  3. 插入排序

  4. 异或运算的应用

    1. 数组中一种数出现了奇数次,其余数出现偶数次,找出这个奇数次的数
      public static void printOddTimesNum1(int[] arr) {
      	int res = 0;
      	for (int cur : arr) {
      		res ^= cur;
      	}
      	System.out.println(res);
      }
    2. 数组中两种数出现了奇数次,其余数出现偶数次,找出这两个奇数次的数
      public static void printOddTimesNum2(int[] arr) {
      	int tmp = 0;
      	for (int cur : arr) {
      		tmp ^= cur;
      	} 
      	// tmp = a ^ b
      	// 因为a != b,所以tmp != 0,即tmp的二进制中必有一个位置上是1
      	
      	int rightOne = tmp & (~tmp + 1); // 取出tmp中最右侧的1,保留权重
      	int res = 0;
      	for (int cur : arr) {
      		if ((cur & rightOne) == 0) {
      			res ^= cur;
      		}
      	}
      	System.out.println(res + " " + (res ^ tmp));
      }
  5. 二分法

    1. 整数数组中的一个局部最优解
    2. 求数组中的最大值(递归)
      public static int getMax(int[] arr) {
      	return process(arr, 0, arr.length - 1);
      }
      
      // 求数组中[L...R]范围上最大值
      public static int process(int[] arr, int L, int R) {
      	if (L == R) { // arr[L...R]范围上只有一个数
      		return arr[L];
      	}
      	int mid = L + ((R - L) >> 1);	// 求中点
      	int leftMax = process(arr, L, mid);
      	int rightMax = process(arr, mid + 1, R);
      	return Math.max(leftMax, rightMax);
      }
  6. master公式:T(N)=a*T(\frac{N}{b})+O(N^{d})

  7.  归并排序

    public class Code01_MergeSort {
    	// 时间复杂度O(N*logN) 空间复杂度O(N)
    	public static void mergeSort(int[] arr) {
    		if (arr.length < 2) {
    			return;
    		}
    		sort(arr, 0, arr.length- 1);
    	}
    	
    	// 递归过程,该函数让arr在L到R的范围内有序
    	private static void sort(int[] arr, int L, int R) {
    		if (L == R) {
    			return;
    		}
    		int mid = L + ((R - L) >> 1);
    		sort(arr, L, mid);
    		sort(arr, mid, R);
    		merge(arr, L, mid, R);
    	}
    	
    	// 归并操作,把arr数组中各自有序的L~mid和mid+1~R两部分合并
    	public static void merge(int[] arr, int L, int mid, int R) {
    		int[] help = new int[R - L + 1]; // 开辟一个等规模的辅助数组
    		int i = 0; // help[]的指针
    		int pl = L; // L~mid部分的指针
    		int pr = mid + 1; // mid+1~R部分的指针
    		while (pl <= mid && pr <= R) {
    			help[i++] = arr[pl] <= arr[pr] ? arr[pl++] : arr[pr++];			
    		}
    		while (pl <= mid) {
    			help[i++] = arr[pl++];
    		}
    		while (pr <= R) {
    			help[i++] = arr[pr++];
    		}
    		// 归并完成,拷贝回原数组
    		for (i = 0; i <= R; i++) {
    			arr[L + i] = help[i];
    		}
    	}
    
    }
     
    1. 小和问题
      1. 描述:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。
    2. 逆序对问题
      1. 描述:在一个数组中,如果左边的数比右边的数大,则这两个数构成一个逆序对,请打印所有的逆序对。
  8. 快速排序

    1. 荷兰国旗问题一
      1. 描述:给定一个数组arr,和一个数num,把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。
      2. 思路: 若[ i ] <= num,则[ i ]和less区的下一个数交换,less区向右扩一个位置,i++ ; 若[ i ] > num,i++。
        public static void hollandFlag1(int[] arr, int num) {    
            // less所指位置及其左侧均小于等于num
        	int less = -1;
        	for (int i = 0; i < arr.length; i++) {
        		if (arr[i] <= num) {
        			swap(arr, i, ++less);
        		}
        	}
        }
        
        public static void swap(int[] arr, int i, int j) {
        	int temp = arr[i];
        	arr[i] = arr[j];
        	arr[j] = temp;  
        }
        
        // Wen_JunRen
    2. 荷兰国旗问题二
      1. 描述:给定一个数组arr,和一个数num,把小于等于num的数放在数组的左边,等于num的数放在中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。
      2. 思路:若[ i ] < num, [ i ]和less区的下一个数交换,less区向右扩一个位置,i++ ; 若[ i ] = num,i++。
        public static void hollandFlag2(int[] arr, int num) {
        	// less所指位置及其左边均小于num,greater所指位置及其右边均大于num
        	int less = -1, greater = arr.length;
        	for (int i = 0; i < greater; i++) {
            // 注意循环终止条件不可以写成 i < arr.length,否则等于num的区域和大于num的区域会交换位置
        		if (arr[i] < num) {
        			swap(arr, i, ++less);
        		} else if (arr[i] > num) {
        			swap(arr, i--, --greater);	
        		}
        	}
        }
        
        // Wen_JunRen
    3. 快速排序的实现

      1. 思想:从数组中随机选一个数作为枢轴(或基准),一趟排序将数组依次划分为左侧小于枢轴元素的部分less、中间等于枢轴元素的部分和右侧大于枢轴元素的部分greater。然后递归地对less和greater进行划分。
      2. 代码
        public class Code04_QuickSort {
        	// 时间复杂度O(N * logN)  空间复杂度O(1)
        	public static void quickSort(int[] arr) {
        		quickSort(arr, 0, arr.length - 1);
        	}
        	
        	public static void quickSort(int[] arr, int L, int R) {
        		if (L < R) {
        			int[] p  = partition(arr, L, R);
        			quickSort(arr, L, p[0]);	// less区
        			quickSort(arr, p[1], R);	// greater区
        		}
        	}
        	
        	// 将arr[L...R]划分成三部分,并返回左右边界
        	public static int[] partition(int[] arr, int L, int R) {
        		// 随机选一个数作为枢纽
        		int pivot = arr[L + (int)(Math.random() * (R - L + 1))];
        		int less = L - 1, greater = R + 1;
        		for (int i = L; i < greater; i++) {
        			if (arr[i] < pivot) {
        				swap(arr, i, ++less);
        			} else if (arr[i] > pivot) {
        				swap(arr, i--, --greater);	
        			}
        		}
        		return new int[] {less, greater};
        	}
        	
        	public static void swap(int[] arr, int i, int j) {
        		int temp = arr[i];
        		arr[i] = arr[j];
        		arr[j] = temp;  
        	}
        // Wen_JunRen
        }
        
  9. 堆排序
    1. 引论
      1. 完全二叉树存储在数组中,父子结点的下标关系:对于第i个结点,其左孩子为2*i+1,右孩子为2*i+2,父结点:( i - 1) / 2。
      2. 大根堆:父结点的值大于所有子孙结点的值,L[ i ] >= L[ 2i + 1]且L[ i ] >= L[2i + 2]。
      3. 小根堆:父结点的值小于所有子孙结点的值,L[ i ] <= L[ 2i + 1]且L[ i ] <= L[2i + 2]。

二、链表

三、二叉树

四、图

五、前缀树和贪心算法

小操作

  1. 用异或运算交换两个数

    // 异或运算交换a和b
    public static void swap(int a, int b) {
    	a = a ^ b;
    	b = a ^ b;
    	a = a ^ b;
    	// tips:异或运算:相同为0,不同为1;也可理解为二进制中无进位相加
    	// attention:使用异或运算交换两个变量的值的前提:两个变量各自拥有独立的内存空间
    }
  2. 用对数器测试代码

    1. 解释:比如自己编写的排序算法,可以生成不定长、不定值的数组测试排序结果,将其与系统排序方法的结果对照。
  3. 生成随机数组

    // 随机生成指定最大长度、最大值的整数数组 	
    public static int[] generateRandomArray(int maxSize, int maxValue) {
    	// Math.rando() -> [0,1)所有小数,等概率返回一个
    	// Math.random() * N -> [0,N)所有小数,等概率返回一个
    	// (int)Math.random() * N -> [0,N-1]所有整数,等概率返回一个
    		
    	int[] arr = new int[(int) (Math.random() * (maxSize + 1))]; // 长度随机
    	for (int i = 0; i < arr.length; i++) { // 元素值随机
    		arr[i] = (int) (Math.random() * (maxValue + 1) - (int) (Math.random() * maxValue));
    	}		
    	return arr;
    }
  4. 不溢出地求两数的平均值

    L < R
    1、一般方法:mid = (L + R) / 2
        当L和R很大时,求L+R时可能会溢出
    2、不溢出的方法:mid = L + (R - L) / 2
    3、简化:mid = L + ((R - L) >> 1)
        右移一位相当于除2

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构算法基础是青岛大学的一个课程,该课程的教学视频可以在Bilibili上观看。视频的链接是。此外,课程还推荐了一本配套的书籍《数据结构 C语言版 第2版严蔚敏/清华大学》。如果你想深入学习该课程,可以通过该链接下载书籍。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [数据结构算法基础-青岛大学-王卓](https://blog.csdn.net/weixin_45433031/article/details/128307330)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [数据结构算法基础(青岛大学-王卓)](https://blog.csdn.net/weixin_47312141/article/details/108908378)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [数据结构算法基础](https://blog.csdn.net/m0_60666279/article/details/127614953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值