一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解 笔记
- 教程与代码地址
- P1 出圈了!讲课之外我们来聊聊算法和数据结构!以及未来!
- P2 1.认识复杂度和简单排序算法
- P3 2.认识O(NlogN)的排序
- P4 3.详解桶排序以及排序内容大总结
- P5 4.链表
- P6 5.二叉树
- P7 6. 图
- P8 7.详解前缀树和贪心算法
- P9 8. 暴力递归
- P10 9. 补充视频
- P11 10.基础提升 哈希函数与哈希表等
- P12 11.基础提升 有序表、并查集等
- P13 12.基础提升 KMP、Manacher算法等
- P14 13.基础提升 滑动窗口、单调栈结构等
- P15 14.基础提升 二叉树的Morris遍历等
- P16 15.基础提升 大数据题目等
- P17 16.基础提升 暴力递归(上)等
- P18 17.基础提升 暴力递归(下)等
- P19 18.中级提升班-1
- P20 19.中级提升班-2
- P21 20.中级提升班-3
- P22 21.中级提升班-4
- P23 22.中级提升班-5
- P24 23.中级提升班-6
- P25 24.中级提升班-7
- P26 25.中级提升班-8
- P27 26.中级提升班-9
- P28 27.中级提升班-10
- P29 28.高级进阶班-1
- P30 29.高级进阶班-2
- P31 30.高级进阶班-3
- P32 31.高级进阶班-4
- P33 32.高级进阶班-5
- P34 33.高级进阶班-6
- P35 34.高级进阶班-7
- P36 35.高级进阶班-8
- P37 36.高级进阶班-9
- P38 37.高级进阶班-10
- P39 38.高级进阶班-11
教程与代码地址
笔记中,图片和代码基本源自up主的视频和代码
视频地址:一周刷爆LeetCode,算法大神左神(左程云)耗时100天打造算法与数据结构基础到高级全家桶教程,直击BTAJ等一线大厂必问算法面试题真题详解
代码地址:
讲义地址:
如果想要爬虫视频网站一样的csdn目录,可以去这里下载代码:https://github.com/JeffreyLeal/MyUtils/tree/%E7%88%AC%E8%99%AB%E5%B7%A5%E5%85%B71
P1 出圈了!讲课之外我们来聊聊算法和数据结构!以及未来!
P2 1.认识复杂度和简单排序算法
数组在内存空间中,是连续的区域;
列表在内存中不是连续的,而是一个指针指向下一个指针。
常数时间的操作:一个操作如果和样本的数据量没有关系,每次都是固定时间内完成的操作,叫做常数操作。比如数组的寻址操作,得到arr[i]的值,只需要起始地址+i就能算到该位置的地址,得到该位置上得值,是常数操作。而列表的寻址,就要逐个遍历,才得到list[i],这就不是常数操作。
基础第一课题目二:选择排序、冒泡排序
选择排序
选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零:
先找最小,次小,次次小…如此类推,一共n轮排序,每轮排序记录次轮比较中最小元素的位置,然后交换。
复杂度,在表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,常数操作复杂度为
O
(
N
2
)
O(N^2)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.06411em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.814108em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span>:<br> <img src="https://img-blog.csdnimg.cn/951784d5607c4635986d34331c169be5.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmVmZnJleUxlYWw=,size_20,color_FFFFFF,t_70,g_se,x_16" alt="在这里插入图片描述"></p>
看:看了多少眼;
比:2数比较,比较应该比看要少一次;
swap:交换,比较的过程只记录第i轮排序和第j个位置的下标,所以每一轮只交换了一次。
代码:
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; } swap(arr, i, minIndex); } }
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">swap</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> i<span class="token punctuation">,</span> <span class="token keyword">int</span> j<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span> tmp <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span> arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> tmp<span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
冒泡排序
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。 它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。 这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
两两比较,大的右移,比较窗口滑动,直到最大的数放到最后,结束一轮比较,再开始下一轮。
此算法时间复杂度也为
O
(
N
2
)
O(N^2)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.06411em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.814108em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span>。</p>
基础第一课题目五:异或运算
异或运算,异或操作性质:一个数与自身异或=自身
位运算,先转换为2进制表示,运算完后,再转回10进制:
public class Test {
public static void main(String[] args) {
int a = 7;
int b = 4;
int c = a^b;
int d = a^b^a;
System.out.println(c);
System.out.println(d);
}
}
控制台:
3
4
Process finished with exit code 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
下面三行代码跑完,2个数完成互换:
这么做的前提2个交换数的内存地址不能一样,不然就是自身与自身异或,结果是0。
例题
1)数组中,一个数出现了奇数次,其他数出现了偶数次,要找奇数次的数
答案:将所有数都异或,最后只剩下奇数次的数。
public static void printOddTimesNum1(int[] arr) {
int eO = 0;
for (int cur : arr) {
eO ^= cur;
}
System.out.println(eO);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
1)数组中,2个数a,b出现了奇数次,其他数出现了偶数次,要找奇数次的数
答案:将所有数都异或,得到eor=a异或b;因为a!=b,所以eor!=0,必造成eor有一个位上为1,那个位就能用来区分a和b。
eor & (~eor + 1);//选出e0最右边的一个1:
public static void printOddTimesNum2(int[] arr) {
int eO = 0, eOhasOne = 0;
for (int curNum : arr) {
eO ^= curNum;
}
int rightOne = eO & (~eO + 1);//选出e0最右边的一个1,
for (int cur : arr) {
if ((cur & rightOne) != 0) {
eOhasOne ^= cur;//最后得到的这个数,是这一个位上有1的数,与其他数的异或
}
}
System.out.println(eOhasOne + " " + (eO ^ eOhasOne));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
基础第一课题目三:插入排序
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动。
算法步骤:
0~1范围有序;
0~2范围有序,将第二个位置的数插入到前面,排好序就停下,所以比较的次数与数据的结构有关。
算法复杂度,只计算最坏情况的复杂度。此算法时间复杂度也为
O
(
N
2
)
O(N^2)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.06411em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.814108em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span>。<br> <img src="https://img-blog.csdnimg.cn/6ea9bf9026ef4c83a11b55d400008e30.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmVmZnJleUxlYWw=,size_9,color_FFFFFF,t_70,g_se,x_16" alt="在这里插入图片描述"></p>
public static void insertionSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
//判断条件,j >= 0:换到最后就停,arr[j] > arr[j + 1]排好序就停
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];
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
基础第一课题目四:二分法的详解与扩展
1)在一个有序数组中,找某个数是否存在
2分找到数就停止。
2)在一个有序数组中,找>=某个数最左侧的位置
2分找到数,还要继续,直到最左侧停止。
3)局部最小值问题,数组无序,任何两个相邻的数不相等,局部最小值定义为既小于左边数,也小于右边数。
用的是零点定理的思想,上图中,3个位置的趋势,左边两个趋势,中间必有最小值。
基础第一课题目六:对数器的概念和使用
使用对数器检查排序算法的准确
算法c是自己写的,算法b是系统提供的排序算法,使用随机数组,2种算法对比,看c是否有错。不依赖线上测试平台,自己就能测出来。
对数器:
public static void comparator(int[] arr) {
Arrays.sort(arr);
}
- 1
- 2
- 3
P3 2.认识O(NlogN)的排序
基础第一课题目七:递归排序
用递归方法找一个数组中的最大值,系统上到底是怎么做的?
求中点,第一行L+R可能会溢出,第三行使用右移一位就是除以2。
递归函数的拆分:
由上往下,不断进栈,多叉树,每一条叉都会进栈出栈,实现遍历。
public static int getMax(int[] arr) { return process(arr, 0, arr.length - 1); }
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token class-name">L</span><span class="token punctuation">,</span> <span class="token keyword">int</span> <span class="token class-name">R</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">L</span> <span class="token operator">==</span> <span class="token class-name">R</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> arr<span class="token punctuation">[</span><span class="token class-name">L</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">int</span> mid <span class="token operator">=</span> <span class="token class-name">L</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">R</span> <span class="token operator">-</span> <span class="token class-name">L</span><span class="token punctuation">)</span> <span class="token operator">>></span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> leftMax <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> <span class="token class-name">L</span><span class="token punctuation">,</span> mid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> rightMax <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> mid <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token class-name">R</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>leftMax<span class="token punctuation">,</span> rightMax<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
使用此公式的前提是子问题的规模要一致。
左边是母问题的复杂度,右边第一项是子问题的复杂度,第二项为其余操作的复杂度。
上述代码,2个子问题的规模都是N/2,加上一次if,一次算中点,一次比较,这3个常数操作的总复杂度是
O
(
1
)
O(1)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord">1</span><span class="mclose">)</span></span></span></span></span>。</p>
基础第二课题目一:归并排序
归并排序的主要思想是分治法。主要过程是: 将n个元素从中间切开,分成两部分。(左边可能比右边多1个数) 将步骤1分成的两部分,再分别进行递归分解。直到所有部分的元素个数都为1。 从最底层开始逐步合并两个排好序的数列
public static void mergeSort(int[] arr) { if (arr == null || arr.length < 2) { return; } mergeSort(arr, 0, arr.length - 1); }
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>l <span class="token operator">==</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">int</span> mid <span class="token operator">=</span> l <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">-</span> l<span class="token punctuation">)</span> <span class="token operator">>></span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> l<span class="token punctuation">,</span> mid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> mid <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">merge</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> l<span class="token punctuation">,</span> mid<span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> m<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> help <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>r <span class="token operator">-</span> l <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span> p1 <span class="token operator">=</span> l<span class="token punctuation">;</span> <span class="token keyword">int</span> p2 <span class="token operator">=</span> m <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p1 <span class="token operator"><=</span> m <span class="token operator">&&</span> p2 <span class="token operator"><=</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//一直往help里面黏贴,同时p1或p2指针一直右移直至越界</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p1<span class="token punctuation">]</span> <span class="token operator"><</span> arr<span class="token punctuation">[</span>p2<span class="token punctuation">]</span> <span class="token operator">?</span> arr<span class="token punctuation">[</span>p1<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">:</span> arr<span class="token punctuation">[</span>p2<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p1 <span class="token operator"><=</span> m<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把没越界的指针后面剩余的数组黏贴到help里面</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p1<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p2 <span class="token operator"><=</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把没越界的指针后面剩余的数组黏贴到help里面</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p2<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> help<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把排好序的help数组黏贴到原始数组的位置</span> arr<span class="token punctuation">[</span>l <span class="token operator">+</span> i<span class="token punctuation">]</span> <span class="token operator">=</span> help<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
子问题mergeSort的规模都是N/2,merge的复杂度是N,母问题的复杂度为
O
(
N
∗
log
N
)
+
O
(
N
)
O(N*\log N)+O(N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。选择排序,冒泡排序,插入排序,都是有大量重复的比较,浪费了比较的信息,而归并排序,用空间换了时间,每次比较都没有被浪费,每次比较都进行排序,所以复杂度低。<br> <img src="https://img-blog.csdnimg.cn/af25d8e2d3384a289a32941f829291ac.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmVmZnJleUxlYWw=,size_20,color_FFFFFF,t_70,g_se,x_16" alt="在这里插入图片描述"></p>
基础第二课题目二:归并排序的扩展
小和问题
直接遍历的复杂度:
问题可以转换为,算一个数,右边有多少个数比他大:比1大有4个,比3大有2个…
其实就是在递归合并里面加了一行代码,计算右边数组中,有多少个数比p1指针所指的数要大。
public static int smallSum(int[] arr) { if (arr == null || arr.length < 2) { return 0; } return mergeSort(arr, 0, arr.length - 1); }
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>l <span class="token operator">==</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">int</span> mid <span class="token operator">=</span> l <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>r <span class="token operator">-</span> l<span class="token punctuation">)</span> <span class="token operator">>></span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> l<span class="token punctuation">,</span> mid<span class="token punctuation">)</span> <span class="token comment">//左侧排序求小和</span> <span class="token operator">+</span> <span class="token function">mergeSort</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> mid <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> r<span class="token punctuation">)</span> <span class="token comment">//右侧侧排序求小和</span> <span class="token operator">+</span> <span class="token function">merge</span><span class="token punctuation">(</span>arr<span class="token punctuation">,</span> l<span class="token punctuation">,</span> mid<span class="token punctuation">,</span> r<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//2侧排序求小和</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">merge</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> m<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> help <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>r <span class="token operator">-</span> l <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span> p1 <span class="token operator">=</span> l<span class="token punctuation">;</span> <span class="token keyword">int</span> p2 <span class="token operator">=</span> m <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token keyword">int</span> res <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p1 <span class="token operator"><=</span> m <span class="token operator">&&</span> p2 <span class="token operator"><=</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> res <span class="token operator">+=</span> arr<span class="token punctuation">[</span>p1<span class="token punctuation">]</span> <span class="token operator"><</span> arr<span class="token punctuation">[</span>p2<span class="token punctuation">]</span> <span class="token operator">?</span> <span class="token punctuation">(</span>r <span class="token operator">-</span> p2 <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> arr<span class="token punctuation">[</span>p1<span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token comment">//记录右边的数组有几个数比左边当前数要大</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p1<span class="token punctuation">]</span> <span class="token operator"><</span> arr<span class="token punctuation">[</span>p2<span class="token punctuation">]</span> <span class="token operator">?</span> arr<span class="token punctuation">[</span>p1<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">:</span> arr<span class="token punctuation">[</span>p2<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">//一直往help里面黏贴,同时p1或p2指针一直右移直至越界,将2个数组合并重排</span> <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p1 <span class="token operator"><=</span> m<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把没越界的指针后面剩余的数组黏贴到help里面</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p1<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>p2 <span class="token operator"><=</span> r<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把没越界的指针后面剩余的数组黏贴到help里面</span> help<span class="token punctuation">[</span>i<span class="token operator">++</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>p2<span class="token operator">++</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> help<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//把排好序的help数组黏贴到原始数组的位置</span> arr<span class="token punctuation">[</span>l <span class="token operator">+</span> i<span class="token punctuation">]</span> <span class="token operator">=</span> help<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> res<span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
逆序对问题
在一个数组中,左边的数如果比右边的数大,则折两个数构成一个逆序对,请打印所有逆序对。
示例:对于0来说,30,20,40,50都是逆序对。
只要涉及数组中,两两比较,再进行操作的,都可以用归并排序。
基础第二课题目六:荷兰国旗问题
小于区域不断往右扩展,遇到比num大的数,就与未比较的区域的数交换,把大于num的数扔到右边,直到小于区域与右边的大于区域相遇。
做法:
小于区域推着等于区域走。
基础第二课题目七:快速排序
1.0版本,用上面问题一和递归的结合
2.0版本,用上面问题二(荷兰国旗问题)和递归的结合
1.0,2.0版本,都有可能遇到划分的极端情况,左边区域很大,右边很小,复杂度就为
O
(
N
2
)
O(N^2)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.06411em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord"><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height: 0.814108em;"><span class="" style="top: -3.063em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span>。</p>
3.0版本,随机选择一个数来划分,那个极端好和极端坏的情况都是等概率事件,复杂度与概率求期望,得到期望复杂度为
O
(
N
log
N
)
O(N\log N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。</p>
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
//将末位数字随机打乱
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);//把当前数归到less区域
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);//把当前数归到more区域
} else {
l++;//推着equal区域右移
}
}
swap(arr, more, r);//把num放到equal区域
return new int[] { less + 1, more };//返回less区域和equal区域的边界,equal区域和more区域的边界
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
P4 3.详解桶排序以及排序内容大总结
不完全二叉树示例:
二叉树结构:
大根堆:父节点的数比子节点的数要大,示例:
利用
新进堆的数与父节点比较,形成大根堆
把新的数插入到堆中,就是上移:
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {//当前节点数值大于父节点位置
swap(arr, index, (index - 1) /2);
index = (index - 1)/2 ;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
某数a在index位置,将其往下移动,至堆结构符合大根堆要求,,就是下移:
//某数a在index位置,将其往下移动
public static void heapify(int[] arr, int index, int size) {//size为数组长度
int left = index * 2 + 1;//左孩子位置
while (left < size) {//判断孩子是否存在
//只有当右孩子存在且大于左孩子时,才取右孩子作为最大值;
//其余情况选左孩子,包括
// 1.右孩子不存在
// 2.右孩子存在但没左孩子大
//largest记录最大值的位置
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
//比较父节点和大孩子之间谁大,记录下大的值的位置
largest = arr[largest] > arr[index] ? largest : index;
//如果父节点比较大,堆结构排好,退出
if (largest == index) {
break;
}
//孩子比较大,交换父和孩子的位置
swap(arr, largest, index);
//记录某数a的新位置
index = largest;
//记录处于新位置的某数a的左孩子
left = index * 2 + 1;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
新增一个数,或删除最大值,调整的复杂度都是
O
(
log
N
)
O(\log N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。</p>
用大根堆来排序:
所有数字先入大根堆,然后将最大数字于heapsize最后一个元素交换,heapsize减一,然后第一个数做heapify的下移操作,如此反复,就能将全部数字排序,调整的复杂度都是
O
(
N
log
N
)
O(N\log N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。<br> <img src="https://img-blog.csdnimg.cn/3e9c03661d0e4099a7576140fdb5a743.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmVmZnJleUxlYWw=,size_20,color_FFFFFF,t_70,g_se,x_16" alt="在这里插入图片描述"></p>
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
//将所有数字搞成大根堆
for (int i = 0; i < arr.length; i++) {// O(N)
heapInsert(arr, i);// O(logN)
}
int size = arr.length;
//0位置上的数与heapsize最后一个数交换
swap(arr, 0, --size);
while (size > 0) {// O(N)
//0位置上的数重新调整位置
heapify(arr, 0, size);// O(logN)
//0位置上的数与heapsize最后一个数交换,heapsize减小
swap(arr, 0, --size);// O(1)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
第一步,全部数字变成大根堆,有优化做法,最小的树做heapify,然后次小…:
假设最底层代价是1,倒数第二层代价是二,如此类推:
复杂度使用错位相加法:
最终复杂度为
O
(
N
)
O( N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。</p>
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
//将所有数字搞成大根堆
//做法1:
// for (int i = 0; i < arr.length; i++) {// O(N)
// heapInsert(arr, i);// O(logN)
// }
//做法2:
for (int i = arr.length-1; i >= 0 ; i--) {
heapify(arr, i, arr.length);
}
int size = arr.length;
//0位置上的数与heapsize最后一个数交换
swap(arr, 0, --size);
while (size > 0) {// O(N)
//0位置上的数重新调整位置
heapify(arr, 0, size);// O(logN)
//0位置上的数与heapsize最后一个数交换,heapsize减小
swap(arr, 0, --size);// O(1)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
基础第二课题目五:堆排序扩展题目
因为0位置上的正确数一定在0-6这七个数中,所以将这7个数在小根堆中排好序,最小值就可以弹出放到0位置上,然后再加入下一个数,进行重复操作。复杂度为
O
(
N
log
k
)
O( N\log k)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.03148em;">k</span><span class="mclose">)</span></span></span></span></span>。</p>
public static void main(String[] args) {
PriorityQueue<Integer> heap = new PriorityQueue<>();
heap.add(8);
heap.add(3);
heap.add(6);
heap.add(2);
heap.add(4);
while (!heap.isEmpty()){
System.out.println(heap.poll());
}
}
输出
2
3
4
6
8
Process finished with exit code 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
public void sortedArrDistanceLessK(int[] arr, int k) {
PriorityQueue<Integer> heap = new PriorityQueue<>();
int index = 0;
//k个数形成小根堆
for (; index < Math.min(arr.length, k); index++) {
heap.add(arr[index]);
}
int i = 0;
for (; index < arr.length; i++, index++) {
heap.add(arr[index]);//加一个数
arr[i] = heap.poll();//弹出一个最小值
}
while (!heap.isEmpty()) {//依次弹出k个最小值
arr[i++] = heap.poll();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
小根堆会遇到不够空间时扩容,扩容就会复制一次,长度为多少,复杂度就为多少,一共扩容 logN 次,总扩容复杂度为
O
(
N
log
N
)
O( N\log N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>,均摊下来每个元素,复杂度为 <span class="katex--inline"><span class="katex"><span class="katex-mathml">
O
(
log
N
)
O( \log N)
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.02778em;">O</span><span class="mopen">(</span><span class="mop">lo<span style="margin-right: 0.01389em;">g</span></span><span class="mspace" style="margin-right: 0.166667em;"></span><span class="mord mathdefault" style="margin-right: 0.10903em;">N</span><span class="mclose">)</span></span></span></span></span>。</p>
系统提供的堆,只能给一个数,弹出一个数,不能做到上述的高效操作,要实现有高效操作的,必须自己写。
基础第三课题目二:桶排序
基于词频,频率的统计,然后还原成有序的数组:
计数排序:
基数排序:
先按个位数放进桶,然后从左往右,先进先出导出,再按十位数排序,重复,再按百位
2:22:00开始看,代码的实现count不是记录桶
i
i
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.65952em; vertical-align: 0em;"></span><span class="mord mathdefault">i</span></span></span></span></span> 里面有多少个数,而是记录 <span class="katex--inline"><span class="katex"><span class="katex-mathml">
≤
i
\leq i
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 0.77194em; vertical-align: -0.13597em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right: 0.277778em;"></span></span><span class="base"><span class="strut" style="height: 0.65952em; vertical-align: 0em;"></span><span class="mord mathdefault">i</span></span></span></span></span> 里面有多少个数。</p>
// only for no-negative value public static void radixSort(int[] arr) { if (arr == null || arr.length < 2) { return; } radixSort(arr, 0, arr.length - 1, maxbits(arr)); } //计算最大的十进制位是第几位 public static int maxbits(int[] arr) { int max = Integer.MIN_VALUE; for (int i = 0; i < arr.length; i++) { max = Math.max(max, arr[i]);//寻找数组中最大的数 } int res = 0; while (max != 0) { res++; max /= 10;//自动整除,因为max是int } return res; }
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">radixSort</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arr<span class="token punctuation">,</span> <span class="token keyword">int</span> begin<span class="token punctuation">,</span> <span class="token keyword">int</span> end<span class="token punctuation">,</span> <span class="token keyword">int</span> digit<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">final</span> <span class="token keyword">int</span> radix <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> bucket <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>end <span class="token operator">-</span> begin <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">//digit多少哥十进制位,也代表入桶出桶的次数</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> d <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> d <span class="token operator"><=</span> digit<span class="token punctuation">;</span> d<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> count <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span>radix<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">//用于记录当前位上等于0,...,等于9的各有多少个数</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> begin<span class="token punctuation">;</span> i <span class="token operator"><=</span> end<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> j <span class="token operator">=</span> <span class="token function">getDigit</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> d<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//确认当位上的数是多少</span> count<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">++</span><span class="token punctuation">;</span><span class="token comment">//等于该位上的数,统计加1</span> <span class="token punctuation">}</span> <span class="token comment">//用于记录当前位上小于等于0,...,小于等于9的各有多少个数</span> <span class="token comment">//同时也记录了当前位上等于0,...,等于9的数组最后一个数出桶后的位置</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><</span> radix<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> count<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> count<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">+</span> count<span class="token punctuation">[</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> end<span class="token punctuation">;</span> i <span class="token operator">>=</span> begin<span class="token punctuation">;</span> i<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> j <span class="token operator">=</span> <span class="token function">getDigit</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> d<span class="token punctuation">)</span><span class="token punctuation">;</span> bucket<span class="token punctuation">[</span>count<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token comment">//出桶后的位置上放该数</span> count<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token operator">--</span><span class="token punctuation">;</span><span class="token comment">//该桶上的数减一</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> begin<span class="token punctuation">,</span> j <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> end<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">,</span> j<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">//把bucket的数组导入arr中,相当于保留了这次桶排序</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> bucket<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
P5 4.链表
基础第三课题目三:排序算法的稳定性及其汇总
不具备稳定性的例子:选择排序
快速排序:
只要有跨度的交换,就会丧失稳定性。
相邻交换的则不会。
具备稳定性的例子:冒泡排序
插入排序:
归并排序关键在于merge的时候,要先拷贝左边的数,而用归并解决小和问题的时候,要先拷贝右边的数,则丧失稳定性:
总结
下面都是没有必要的**改进
在快速排序中,当样本量小于60的时候,插入排序时间复杂度相当,当常数操作复杂度极低,因此可以将2种混合起来。
基础第四课题目一:哈希表的简单介绍
hashset 和 hashmap
String、Integer这些都算基础类型。
基础第四课题目二:有序表的简单介绍
把列表扔到栈,然后弹出一个比对一个
使用快慢指针,快指针结束的时候,慢指针走到中点。这个coding要练熟。
如果要使用低空间复杂度,使用改链表的方式,最后再恢复:
// need O(1) extra space
public static boolean isPalindrome3(Node head) {
if (head == null || head.next == null) {
return true;
}
Node n1 = head;//慢指针
Node n2 = head;//快指针
//快慢指针找末尾和中点
while (n2.next != null && n2.next.next != null) { // find mid node
n1 = n1.next; // n1 -> mid
n2 = n2.next.next; // n2 -> end
}
n2 = n1.next; // n2 -> right part first node
n1.next = null; // mid.next -> null
Node n3 = null;//用于记录n2原本的下一个node
//右半部分逆序
while (n2 != null) { // right part convert
n3 = n2.next; // n3 -> save next node,保留未改变的链表
n2.next = n1; // next of right node convert,改变链表指向
//n1,n2两个指针完成改变指向操作后,同时右移,准备下一个元素的链表指向逆序
n1 = n2; // n1 move
n2 = n3; // n2 move
}
n3 = n1; // n3 -> save last node
n2 = head;// n2 -> left first node
boolean res = true;
while (n1 != null && n2 != null) { // check palindrome
//每走一步,都验证
if (n1.value != n2.value) {
res = false;
break;
}
//n1,n2从中间开始走
n1 = n1.next; // left to mid
n2 = n2.next; // right to mid
}
n1 = n3.next;
n3.next = null;
//最后将逆序的链表变回来
while (n1 != null) { // recover list
n2 = n1.next;
n1.next = n3;
n3 = n1;
n1 = n2;
}
return res;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
基础第四课题目九:按某值划分单向链表
笔试:创建node数组,把链表的node烤进去,再做partition,快速排序,即归并的3.0版本。
面试:使用6个变量指针,小于区域的头和尾,等于区域的头和尾,大于区域的头和尾,最后将3个区域连起来的时候,要注意是否有区域为空。
public static Node listPartition2(Node head, int pivot) {
Node sH = null; // small head
Node sT = null; // small tail
Node eH = null; // equal head
Node eT = null; // equal tail
Node bH = null; // big head
Node bT = null; // big tail
Node next = null; // save next node
// every node distributed to three lists
while (head != null) {
next = head.next;
head.next = null;
if (head.value < pivot) {
if (sH == null) {
sH = head;
sT = head;
} else {
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
if (eH == null) {
eH = head;
eT = head;
} else {
eT.next = head;
eT = head;
}
} else {
if (bH == null) {
bH = head;
bT = head;
} else {
bT.next = head;
bT = head;
}
}
head = next;
}
// small and equal reconnect
if (sT != null) {
sT.next = eH;
eT = eT == null ? sT : eT;
}
// all reconnect
if (eT != null) {
eT.next = bH;
}
return sH != null ? sH : eH != null ? eH : bH;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
基础第四课题目十:复制含有随机指针节点的链表
做法1:第一次遍历旧链表,使用哈希map,key为旧链表,value为新链表,新链表只是单纯地串起来并拷贝int value值,rand没有设置;第二次遍历旧链表,调用key-value,设置rand node。
做法2:第一次遍历旧链表,不用哈希map,在旧map中,插入克隆node,拷贝int value值;第二次遍历链表,一对一对处理,设置rand node;第三次遍历,把旧节点删除。省去了hashmap的空间。
P6 5.二叉树
基础第四课题目十一:两个单链表相交
leetcode142题。
判断有环还是无环:
使用额外空间方法:使用hashset,把元素放进集合,判断是否存在;
不使用额外空间的方法:使用快慢指针,快指针走到空,就是无环,快慢指针相遇,就是有环。快慢指针第一次相遇之后,将快指针重置由头开始,慢指针在相遇处,同时再次出发,相遇的地方,就是环的入口。
判断环入口节点代码:
//获取环的入口
public static Node getLoopNode(Node head) {
if (head == null || head.next == null || head.next.next == null) {
return null;
}
Node n1 = head.next; // n1 -> slow
Node n2 = head.next.next; // n2 -> fast
while (n1 != n2) {
//判断快指针是否走完
if (n2.next == null || n2.next.next == null) {
return null;
}
n2 = n2.next.next;
n1 = n1.next;
}
n2 = head; // n2 -> walk again from head
while (n1 != n2) {
n1 = n1.next;
n2 = n2.next;
}
return n1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
情况1:2个链表都是无环,只可能是2条线,或者y型线,不可能是x型,x型就是节点处next指针指向2个地方,这是不可能的。2个链表如果相交,那么他们end端一定是地址一样的,2个链表都遍历。如果相交,要找到节点处,长的列表先走
∣
l
e
n
l
o
n
g
−
l
e
n
s
h
o
r
t
∣
|len_{long}-len_{short}|
</span><span class="katex-html"><span class="base"><span class="strut" style="height: 1.03611em; vertical-align: -0.286108em;"></span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right: 0.01968em;">l</span><span class="mord mathdefault">e</span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight" style="margin-right: 0.01968em;">l</span><span class="mord mathdefault mtight">o</span><span class="mord mathdefault mtight">n</span><span class="mord mathdefault mtight" style="margin-right: 0.03588em;">g</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.286108em;"><span class=""></span></span></span></span></span></span><span class="mspace" style="margin-right: 0.222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right: 0.222222em;"></span></span><span class="base"><span class="strut" style="height: 1em; vertical-align: -0.25em;"></span><span class="mord mathdefault" style="margin-right: 0.01968em;">l</span><span class="mord mathdefault">e</span><span class="mord"><span class="mord mathdefault">n</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height: 0.336108em;"><span class="" style="top: -2.55em; margin-left: 0em; margin-right: 0.05em;"><span class="pstrut" style="height: 2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mord mathdefault mtight">h</span><span class="mord mathdefault mtight">o</span><span class="mord mathdefault mtight" style="margin-right: 0.02778em;">r</span><span class="mord mathdefault mtight">t</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height: 0.15em;"><span class=""></span></span></span></span></span></span><span class="mord">∣</span></span></span></span></span> 步,然后一起走,一定会在交点处相遇。<br> <img src="https://img-blog.csdnimg.cn/59569be7cdf44a6dba35aa315fe53421.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBASmVmZnJleUxlYWw=,size_20,color_FFFFFF,t_70,g_se,x_16" alt="在这里插入图片描述"></p>
public static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;//用于记录长度,先记录链表1长度,然后
//减去链表2的长度,差值的绝对值,就是长度差值
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {//长链表先走差值步
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
情况2:一个为无环,一个有环,那么必然不想交;
情况3:2个都是有环,又分3种情况:
情况3-1:2个不同的有环;
情况3-2:入环节点是同一个,最好判断,分别找到入环节点,如果入环节点不同就是情况3-1或者3-3,如果入环节点相同,就使用上面的无环代码去找相交节点;
情况3-3:入环节点不是同一个;让loop1继续走,在走会自己之前,判断会不会遇到loop2这个入口节点,遇到就是情况3-3,没有就是情况3-1;
//两个有环链表。返回第一个相交节点,如果不想交返回null
//loop1,loop2分别为2个链表的环入口处节点
public static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {//如果入环节点相同,是情况3-2
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {//如果入环节点不同,是情况3-1或3-3
cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;//情况3-3
}
cur1 = cur1.next;
}
return null;//情况3-1
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
基础第五课题目一:二叉树节点结构
1:06:00附近解释先序中序后续,遍历会3次遇到同一个节点,第几次遇到时打印,就是什么序。
更详细的可以看代码随想录 刷题攻略 二叉树 笔记
递归代码:
//先序遍历
public static void preOrderRecur(Node head) {
if (head == null) {
return;
}
System.out.print(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
//中序遍历
public static void inOrderRecur(Node head) {
if (head == null) {
return;
}
inOrderRecur(head.left);
System.out.print(head.value + " ");
inOrderRecur(head.right);
}
//后序遍历
public static void posOrderRecur(Node head) {
if (head == null) {
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.print(head.value + " ");
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
非递归遍历:
先序:
后续:
中序:
//非递归先序遍历,头左右的顺序
public static void preOrderUnRecur(Node head) {
System.out.print("pre-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()) {
//1.弹出一个节点
head = stack.pop();
System.out.print(head.value + " ");
//2.往栈加入节点,先右子节点后左子节点(如果有)
if (head.right != null) {
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
//非递归中序遍历,左头右的顺序
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
//1.所有的左子节点全部进栈
stack.push(head);
head = head.left;
} else {
//2.弹出栈一个节点,如果有右子节点,对右子节点周而复始上述操作
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
//非递归后序遍历,左右头的顺序
public static void posOrderUnRecur1(Node head) {
System.out.print("pos-order: ");
if (head != null) {
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();//收集栈
s1.push(head);
while (!s1.isEmpty()) {
//1.从s1弹出一个节点,放入收集站s2
head = s1.pop();
s2.push(head);
//2.先压左子节点进收集站,后压右子节点进收集站
if (head.left != null) {
s1.push(head.left);
}
if (head.right != null) {
s1.push(head.right);
}
}
while (!s2.isEmpty()) {
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
对中序的解释:先左再头再右,将右分解为先左后头。
也叫层次遍历,使用队列而不是栈,队列是先进先出。
1:58:30附近,求最大宽度,方法1,使用hashmap
方法2,不使用hashmap,使用队列
对于二叉树来说,深度优先遍历就是先序遍历
P7 6. 图
基础第五课题目二:二叉树的相关概念及其实现判断
判断是否搜索二叉树
搜索二叉树,每个节点的左子节点及其子树都比自己小,右子节点及其子树都比自己大:
中序遍历,结果升序,就是搜索二叉树。把中序遍历的打印操作换成比较值的大小。
public static boolean isBST(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> inOrderList = new LinkedList<>();
//保留中序次序
process(head, inOrderList);
int pre = Integer.MIN_VALUE;
//遍历中序次序,看是否由小到大
for (Node cur : inOrderList) {
if (pre >= cur.value) {
return false;
}
pre = cur.value;
}
return true;
}
//递归中序遍历,把原来的打印换成把节点添加到新列表,保留中序次序
public static void process(Node node, LinkedList<Node> inOrderList) {
if (node == null) {
return;
}
process(node.left, inOrderList);
inOrderList.add(node);
process(node.right, inOrderList);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
使用黑盒递归套路:
先更新最大最小值,再做违规判断,返回true or false:
//黑盒子方法套路判断是否是搜索二叉树 public static boolean isBST1(Node head) { return process(head).isBST; } //由于递归的返回值有3个,所有要构造一个类接受这3个返回值 public static class ReturnType { public boolean isBST;//是否是搜索二叉树 public int min; public int max;
<span class="token keyword">public</span> <span class="token class-name">ReturnType</span><span class="token punctuation">(</span><span class="token keyword">boolean</span> isBST<span class="token punctuation">,</span> <span class="token keyword">int</span> min<span class="token punctuation">,</span> <span class="token keyword">int</span> max<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">this</span><span class="token punctuation">.</span>isBST <span class="token operator">=</span> isBST<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>min <span class="token operator">=</span> min<span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>max <span class="token operator">=</span> max<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ReturnType</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">Node</span> x<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span><span class="token comment">//base情况,空节点的返回值</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">ReturnType</span> leftData <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>left<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ReturnType</span> rightData <span class="token operator">=</span> <span class="token function">process</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>right<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">int</span> min <span class="token operator">=</span> x<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token keyword">int</span> max <span class="token operator">=</span> x<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token comment">//先用子树的最大最小值更新此节点的最大最小值</span> <span class="token keyword">if</span><span class="token punctuation">(</span>leftData <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> min <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>min<span class="token punctuation">,</span>leftData<span class="token punctuation">.</span>min<span class="token punctuation">)</span><span class="token punctuation">;</span> max <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>max<span class="token punctuation">,</span>leftData<span class="token punctuation">.</span>max<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span><span class="token punctuation">(</span>rightData <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> min <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span>min<span class="token punctuation">,</span>rightData<span class="token punctuation">.</span>min<span class="token punctuation">)</span><span class="token punctuation">;</span> max <span class="token operator">=</span> <span class="token class-name">Math</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span>max<span class="token punctuation">,</span>rightData<span class="token punctuation">.</span>max<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">boolean</span> isBST <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> <span class="token comment">//判断子树是否违规,违规条件:</span> <span class="token comment">//违规情况1:左子树存在,且它的最大值大于父节点或者</span> <span class="token comment">//左子树不是搜索二叉树</span> <span class="token keyword">if</span><span class="token punctuation">(</span>leftData <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span><span class="token punctuation">(</span><span class="token operator">!</span>leftData<span class="token punctuation">.</span>isBST <span class="token operator">||</span> leftData<span class="token punctuation">.</span>max <span class="token operator">>=</span> x<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> isBST <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//违规情况2:右子树存在,且它的最小值小于父节点或者</span> <span class="token comment">//右子树不是搜索二叉树</span> <span class="token keyword">if</span><span class="token punctuation">(</span>rightData <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span><span class="token punctuation">(</span><span class="token operator">!</span>rightData<span class="token punctuation">.</span>isBST <span class="token operator">||</span> rightData<span class="token punctuation">.</span>max <span class="token operator"><=</span> x<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span> isBST <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ReturnType</span><span class="token punctuation">(</span>isBST<span class="token punctuation">,</span> min<span class="token punctuation">,</span>max<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
判断是否完全二叉树
//按宽度遍历,即按层遍历 public static boolean isCBT(Node head) { if (head == null) { return true; } LinkedList<Node> queue = new LinkedList<>(); boolean leaf = false;//用来记录是否出现过某个节点左右子节点不全的情况 Node l = null; Node r = null; queue.add(head); while (!queue.isEmpty()) { head = queue.poll(); l = head.left; r = head.right; if ( //情况二,在不违反情况一的条件下,在首次出现 //某个节点左右子节点不全的情况后,后续节点必 //须都是叶节点,如果不满足,则返回false (leaf && (l != null || r != null))
<span class="token operator">||</span> <span class="token comment">//情况一:右节点存在,左节点不存在,返回false</span> <span class="token punctuation">(</span>l <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">&&</span> r <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token