Skip to content

Commit 5525a10

Browse files
author
xing dali
committed
添加题143,141
1 parent 4e20e2e commit 5525a10

File tree

3 files changed

+236
-6
lines changed

3 files changed

+236
-6
lines changed

入门(Java)/JS实现.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
### 排序算法
2+
3+
| 算法 | 稳定 | 原地排序 | 时间复杂度 | 空间复杂度 | 备注 |
4+
| :--------------: | :--: | :------: | :--------------------------: | :--------: | :----------------------: |
5+
| 冒泡排序 | yes | yes | N^2^ | 1 | |
6+
| 选择排序 | no | yes | N<sup>2sup> | 1 | |
7+
| 插入排序 | yes | yes | N \~ N<sup>2sup> | 1 | 时间复杂度和初始顺序有关 |
8+
| 希尔排序 | no | yes | N 的若干倍乘于递增序列的长度 | 1 | |
9+
| 快速排序 | no | yes | NlogN | logN | |
10+
| 三向切分快速排序 | no | yes | N \~ NlogN | logN | 适用于有大量重复主键 |
11+
| 归并排序 | yes | no | NlogN | N | |
12+
| 堆排序 | no | yes | NlogN | 1 | |
13+
14+
#### 选择排序
15+
16+
```java
17+
public void swap(int[] T,int i,int j){
18+
int temp = T[i];
19+
T[i] = T[j];
20+
T[j] = temp;
21+
}
22+
23+
public int[] selectSort(int[] nums){//选择排序
24+
for (int i=0;i<nums.length-1;i++){
25+
int min=i;
26+
for (int j=i+1;j<nums.length;j++){
27+
if (nums[j]<nums[min]){
28+
min=j; //选择最小的元素index
29+
}
30+
}
31+
swap(nums,i,min); //交换到最前面
32+
}
33+
return nums;
34+
}
35+
```
36+
37+
#### 冒泡排序
38+
39+
```java
40+
public int[] bubbleSort(int[] nums){
41+
boolean isSort = false; //如果数组已经排好序,就只需要遍历一遍
42+
for (int i=nums.length-1;i>0&&!isSort;i--){
43+
isSort=true;
44+
for (int j=0;j<i;j++){
45+
if (nums[j]>nums[j+1]){//将大的元素向上冒泡
46+
isSort=false;
47+
swap(nums,j,j+1);
48+
}
49+
}
50+
}
51+
return nums;
52+
}
53+
```
54+
55+
#### 插入排序
56+
57+
```java
58+
public int[] insertSort(int[] nums){
59+
for (int i=0;i<nums.length-1;i++){
60+
for (int j=i+1;j>0&&nums[j]<nums[j-1];j--){ //将小元素交换到之前已经排序的数组中去
61+
swap(nums,j,j-1);
62+
}
63+
}
64+
return nums;
65+
}
66+
```
67+
68+
#### 希尔排序
69+
70+
```java
71+
public void shellSort(int[] nums){
72+
int N=nums.length;
73+
int h=1; // h=N/2 就是以1,2,4的增量进行插入排序
74+
while (h < N / 3) {
75+
h = 3 * h + 1; // 1, 4, 13, 40, ...
76+
}
77+
while (h >= 1) {
78+
for (int i = h; i < N; i++) { //循环内是插入排序
79+
for (int j = i; j >= h && nums[j]<nums[j - h]; j -= h) {
80+
swap(nums, j, j - h);
81+
}
82+
}
83+
h = h / 3;
84+
}
85+
}
86+
```
87+
88+
#### 归并排序
89+
90+
```java
91+
public int[] mergeSort(int[] arr,int left,int right){
92+
if (left==right) return new int[] {arr[left]};
93+
int mid = left+(right-left)/2;
94+
int[] leftarr = mergeSort(arr,left,mid); //递归
95+
int[] rightarr = mergeSort(arr,mid+1,right);
96+
int[] newarr = new int[leftarr.length+rightarr.length];
97+
int i=0,j=0,k=0;
98+
while (i< leftarr.length && j< rightarr.length){
99+
newarr[k++] = leftarr[i]<rightarr[j]? leftarr[i++]: rightarr[j++];
100+
}
101+
while (i< leftarr.length){
102+
newarr[k++] = leftarr[i++];
103+
}
104+
while (j<rightarr.length){
105+
newarr[k++] = rightarr[j++];
106+
}
107+
return newarr;
108+
}
109+
```
110+
111+
#### 快速排序
112+
113+
```java
114+
public void quickSort(int[] arr,int start,int end){
115+
int left=start,right=end;
116+
int pivot=arr[start];
117+
while (left<right) { //两个指针
118+
while (arr[right]>pivot && right>left){ //从右指向左,遇到比基准小的换到前面去
119+
right--;
120+
}
121+
while (arr[left]<pivot && right>left){//从左指向右,遇到比基准大的换到后面去
122+
left++;
123+
}
124+
if (arr[left]==arr[right] && left<right){
125+
left++;
126+
}else swap(arr,left,right);
127+
}
128+
if (left-1>start) quickSort(arr,start,left-1);
129+
if (right+1<end) quickSort(arr,right+1,end);
130+
}
131+
```
132+
133+
#### 堆排序
134+
135+
```java
136+
public static int[] heapSort(int[] array) {
137+
//这里元素的索引是从0开始的,所以最后一个非叶子结点array.length/2 - 1
138+
for (int i = array.length / 2 - 1; i >= 0; i--) {
139+
adjustHeap(array, i, array.length); //调整堆
140+
}
141+
// 上述逻辑,建堆结束
142+
// 下面,开始排序逻辑
143+
for (int j = array.length - 1; j > 0; j--) {
144+
// 元素交换,作用是去掉大顶堆
145+
// 把大顶堆的根元素,放到数组的最后;换句话说,就是每一次的堆调整之后,都会有一个元素到达自己的最终位置
146+
swap(array, 0, j);
147+
// 元素交换之后,毫无疑问,最后一个元素无需再考虑排序问题了。
148+
// 接下来我们需要排序的,就是已经去掉了部分元素的堆了,这也是为什么此方法放在循环里的原因
149+
// 而这里,实质上是自上而下,自左向右进行调整的
150+
adjustHeap(array, 0, j);
151+
}
152+
return array;
153+
}
154+
/**
155+
* 整个堆排序最关键的地方
156+
* @param array 待组堆
157+
* @param i 起始结点
158+
* @param length 堆的长度
159+
*/
160+
public static void adjustHeap(int[] array, int i, int length) {
161+
// 先把当前元素取出来,因为当前元素可能要一直移动
162+
int temp = array[i];
163+
for (int k = 2 * i + 1; k < length; k = 2 * k + 1) { //2*i+1为左子树i的左子树(因为i是从0开始的),2*k+1为k的左子树
164+
// 让k先指向子节点中最大的节点
165+
if (k + 1 < length && array[k] < array[k + 1]) { //如果有右子树,并且右子树大于左子树
166+
k++;
167+
}
168+
//如果发现结点(左右子结点)大于根结点,则进行值的交换
169+
if (array[k] > temp) {
170+
swap(array, i, k);
171+
// 如果子节点更换了,那么,以子节点为根的子树会受到影响,所以,循环对子节点所在的树继续进行判断
172+
i = k;
173+
} else { //不用交换,直接终止循环
174+
break;
175+
}
176+
}
177+
}
178+
```
179+

入门(Java)/力扣经典算法.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ public void traversePreOrder(Node node) { //递归
6565
```
6666

6767
```java
68-
public void traversePreOrderWithoutRecursion() {//非递归
68+
public void traversePreOrderWithoutRecursion() { //非递归
6969
Stack<Node> stack = new Stack<Node>();
7070
Node current = root;
7171
stack.push(root);
7272
while(!stack.isEmpty()) {
73-
current = stack.pop();//先根后左子树、右子树
73+
current = stack.pop(); //先根后左子树、右子树
7474
visit(current.value);
7575

7676
if(current.right != null) {

数据结构篇/链表.md

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ var deleteDuplicates = function(head) {
5151
};
5252
```
5353

54-
##### 82.删除排序链表中的重复元素Ⅱ(删除重复数字的节点,只保留没有重复数字的节点)[remove-duplicates-from-sorted-list-ii](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/)
54+
##### 82.删除排序链表中的重复元素Ⅱ[remove-duplicates-from-sorted-list-ii](https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/)
5555

56-
> 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现的数字
56+
> 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字
5757
5858
```js
5959
var deleteDuplicates = function(head) {
@@ -125,7 +125,7 @@ var reverseBetween = function(head, m, n) {
125125
};
126126
```
127127

128-
##### 21.合并两个有序链表
128+
##### [21. 合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)
129129

130130
将两个升序链表合并为一个新的 **升序** 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
131131

@@ -169,7 +169,7 @@ var mergeTwoLists = function(l1, l2) {
169169
};
170170
```
171171

172-
##### 86.分隔链表 [分隔链表](https://leetcode-cn.com/problems/partition-list/)
172+
##### 86.[分隔链表](https://leetcode-cn.com/problems/partition-list/)
173173

174174
给定一个链表和一个特定值 *x*,对链表进行分隔,使得所有小于 *x* 的节点都在大于或等于 *x* 的节点之前。你应当保留两个分区中每个节点的初始相对位置。
175175

@@ -200,3 +200,54 @@ var partition = function(head, x) {
200200
};
201201
```
202202

203+
##### [148. 排序链表](https://leetcode-cn.com/problems/sort-list/)
204+
205+
##### [143. 重排链表](https://leetcode-cn.com/problems/reorder-list/)
206+
207+
给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
208+
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
209+
210+
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
211+
212+
```js
213+
var reorderList = function (head) {
214+
const nodeArr = []
215+
let node = head
216+
while (node !== null) {
217+
nodeArr.push(node)
218+
node = node.next
219+
}
220+
let i = 0, j = nodeArr.length - 1
221+
while (i < j) {
222+
nodeArr[i].next = nodeArr[j]
223+
i++
224+
if (i === j) break
225+
nodeArr[j].next = nodeArr[i]
226+
j--
227+
}
228+
nodeArr[i].next = null
229+
}
230+
```
231+
232+
##### [141. 环形链表](https://leetcode-cn.com/problems/linked-list-cycle/)
233+
234+
给定一个链表,判断链表中是否有环。
235+
236+
```js
237+
var hasCycle = function (head) {
238+
if (head === null || head.next === null) {
239+
return false
240+
}
241+
let slow = head
242+
let fast = head.next
243+
while (fast !== null && fast.next !== null && slow !== null) {
244+
if (slow === fast) {
245+
return true
246+
}
247+
slow = slow.next
248+
fast = fast.next.next
249+
}
250+
return false
251+
}
252+
```
253+

0 commit comments

Comments
 (0)