课程内容更新

This commit is contained in:
MYP 2020-12-02 11:25:28 +08:00
parent b7776ed48e
commit 93f798e09b
19 changed files with 12 additions and 5695 deletions

View File

@ -1,4 +1,4 @@
# 02 C#语言基本语法结构
# 01 C#语言基本语法结构
**知识结构:**

View File

@ -1,4 +1,4 @@
# 03 C#面向对象设计 I
# 02 C#面向对象设计 I
**知识结构:**

View File

@ -1,7 +1,7 @@
# 04 C#面向对象设计 II
# 03 C#面向对象设计 II
**知识结构:**

View File

@ -1,4 +1,4 @@
# 绪论
# 01 绪论
知识结构:

View File

@ -1,6 +1,6 @@
# 09 栈与递归
# 03 栈与递归
**知识结构:**
@ -16,7 +16,7 @@
插入入栈和删除出栈操作只能在一端栈顶进行的线性表。即先进后出First In Last Out的线性表。
例1 :线性表`$(a_0,a_1,?,a_{n-1)}$`进栈与出栈演示。
例1 :线性表 $(a_0,a_1,?,a_{n-1)}$ 进栈与出栈演示。
![图2 顺序表模拟入栈、出栈](https://img-blog.csdnimg.cn/20191222213645860.png)

View File

@ -1,5 +1,5 @@
# 10 队列与多线程
# 04 队列与多线程
**知识结构:**

View File

@ -1,791 +0,0 @@
# Leetcode同步练习
## 题目01两数之和
> - 题号1
> - 难度:简单
> - https://leetcode-cn.com/problems/two-sum/
给定一个整数数组 `nums` 和一个目标值 `target`,请你在该数组中找出和为目标值的那 <b>两个整数</b>,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
**示例1:**
```c
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9所以返回 [0, 1]
```
**示例2**
```c
给定 nums = [230, 863, 916, 585, 981, 404, 316, 785, 88, 12, 70, 435, 384, 778, 887, 755, 740, 337, 86, 92, 325, 422, 815, 650, 920, 125, 277, 336, 221, 847, 168, 23, 677, 61, 400, 136, 874, 363, 394, 199, 863, 997, 794, 587, 124, 321, 212, 957, 764, 173, 314, 422, 927, 783, 930, 282, 306, 506, 44, 926, 691, 568, 68, 730, 933, 737, 531, 180, 414, 751, 28, 546, 60, 371, 493, 370, 527, 387, 43, 541, 13, 457, 328, 227, 652, 365, 430, 803, 59, 858, 538, 427, 583, 368, 375, 173, 809, 896, 370, 789], target = 542
因为 nums[28] + nums[45] = 221 + 321 = 542所以返回 [28, 45]
```
**参考代码:**
思路:直接利用暴力匹配算法。
- 执行结果:通过
- 执行用时432 ms, 在所有 C# 提交中击败了 65.82% 的用户
- 内存消耗30.8 MB, 在所有 C# 提交中击败了 8.67% 的用户
```c
public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
int[] result = new int[2];
for (int i = 0; i < nums.Length - 1; i++)
{
int find = target - nums[i];
for (int j = i + 1; j < nums.Length; j++)
{
if (find == nums[j])
{
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
}
}
```
---
## 题目02删除排序数组中的重复项
> - 题号26
> - 难度:简单
> - https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/
给定一个 **排序数组**,你需要在 **原地** 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 **原地修改输入数组** 并在使用 O(1) 额外空间的条件下完成。
<b>示例 1</b>:
```c
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
```
<b>示例 2</b>:
```c
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
```
<b>说明</b>:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“**引用**”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
```c
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
```
**参考代码:**
思路:双索引法,就是一个快索引一个慢索引,`j`快`i`慢,当`nums[j] == nums[i]`时,`j++`就可以跳过重复项,不相等时,让`i++`并让`nums[i] = nums[j]`,把值复制过来继续执行到末尾即可,时间复杂度为`O(n)`。
- 执行结果:通过
- 执行用时300 ms, 在所有 C# 提交中击败了 64.43% 的用户
- 内存消耗33.5 MB, 在所有 C# 提交中击败了 5.48% 的用户
```c
public class Solution
{
public int RemoveDuplicates(int[] nums)
{
if (nums.Length < 2)
return nums.Length;
int i = 0;
for (int j = 1; j < nums.Length; j++)
{
if (nums[j] != nums[i])
{
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
}
```
---
## 题目03移除元素
> - 题号27
> - 难度:简单
> - https://leetcode-cn.com/problems/remove-element/
给定一个数组`nums`和一个值`val`,你需要**原地**移除所有数值等于`val`的元素,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在**原地修改输入数组**并在使用 O(1) 额外空间的条件下完成。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
**示例 1:**
```c
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
```
**示例 2:**
```c
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
```
**示例 3:**
```c
输入:[] value = 0
输出0
```
**示例 4:**
```c
输入:[1] value = 1
输出0
```
**示例 5:**
```c
输入:[4,5] value = 5
输出1
```
**说明:**
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“**引用**”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
```c
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
```
**参考代码:**
思路:双索引法,利用双索引`i`和`j``i`为慢索引拖后,`j`为快索引向前冲。如果`nums[j]!=val`,将`num[j]`的值赋给`num[i]`,循环结束后,`i`指针前面的元素,即为需要保留的元素,从而达到了移除元素的目的,时间复杂度为 `O(n)`
- 执行结果:通过
- 执行用时272 ms, 在所有 C# 提交中击败了 94.41% 的用户
- 内存消耗29.9 MB, 在所有 C# 提交中击败了 5.21% 的用户
```c
public class Solution
{
public int RemoveElement(int[] nums, int val)
{
int i = 0;
for (int j = 0; j < nums.Length; j++)
{
if (nums[j] != val)
{
nums[i] = nums[j];
i++;
}
}
return i;
}
}
```
---
## 题目04最大子序和
> - 题号53
> - 难度:简单
> - https://leetcode-cn.com/problems/maximum-subarray/
给定一个整数数组`nums`,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
<b>示例 1</b>:
```c
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
```
<b>示例 2</b>:
```c
输入: [-2,1],
输出: 1
```
<b>进阶</b>:
如果你已经实现复杂度为`O(n)`的解法,尝试使用更为精妙的分治法求解。
**参考代码:**
思路:利用暴力算法。
- 状态:通过
- 执行用时: 596 ms, 在所有 C# 提交中击败了 14.18% 的用户
- 内存消耗: 24.5 MB, 在所有 C# 提交中击败了 5.88% 的用户
```c
public class Solution {
public int MaxSubArray(int[] nums) {
int len = nums.Length;
if (len == 0)
return 0;
if (len == 1)
return nums[0];
int max = int.MinValue;
for (int i = 0; i < len; i++)
{
int sum = nums[i];
if (sum > max)
{
max = sum;
}
for (int j = i + 1; j < len; j++)
{
sum += nums[j];
if (sum > max)
{
max = sum;
}
}
}
return max;
}
}
```
---
## 题目05盛最多水的容器
> - 题号11
> - 难度:中等
> - https://leetcode-cn.com/problems/container-with-most-water/
给定`n`个非负整数`a1a2...an`,每个数代表坐标中的一个点`(i, ai)`。在坐标内画`n`条垂直线,垂直线`i` 的两个端点分别为`(i, ai)`和`(i, 0)`。找出其中的两条线,使得它们与`x`轴共同构成的容器可以容纳最多的水。
<b>说明</b>:你不能倾斜容器,且`n`的值至少为 2。
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hbGl5dW4tbGMtdXBsb2FkLm9zcy1jbi1oYW5nemhvdS5hbGl5dW5jcy5jb20vYWxpeXVuLWxjLXVwbG9hZC91cGxvYWRzLzIwMTgvMDcvMjUvcXVlc3Rpb25fMTEuanBn?x-oss-process=image/format,png)
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
<b>示例</b>:
```c
输入: [1,8,6,2,5,4,8,3,7]
输出: 49
```
**参考代码:**
思路:利用双索引的方法。
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9waWMubGVldGNvZGUtY24uY29tLzg4NGQ1YmNlOTU1ZThiYzA1MGY2NTUxNTQwNGEwNDI2NGYyYzFmZjgyNzYyMWFiZDcyYjgxNzA5ZmUzNzMyM2YtJUU5JTgxJThEJUU1JThFJTg2JUU3JTlBJTg0JUU2JTgzJTg1JUU1JTg2JUI1LmpwZw?x-oss-process=image/format,png)
以0-7走到1-7这一步为例解释为什么放弃0-6这一分支
```c
用h(i)表示第i条线段的高度S(ij)表示第i条线段和第j条线段圈起来的面积。
已知 h(0) < h(7)从而S(07) = h(0) * 7
有S(06) = min(h(0), h(6)) * 6。
当h(0) <= h(6)有S(06) = h(0) * 6
当h(0) > h(6)有S(06) = h(6) * 6S(06) < h(0) * 6。
由此可知S(06)必然小于S(07)。
```
把每一棵子树按照同样的方法分析,很容易可以知道,双索引法走的路径包含了最大面积。
- 状态:通过
- 50 / 50 个通过测试用例
- 执行用时: 144 ms, 在所有 C# 提交中击败了 99.64% 的用户
- 内存消耗: 26.6 MB, 在所有 C# 提交中击败了 5.45% 的用户
```c
public class Solution
{
public int MaxArea(int[] height)
{
int i = 0, j = height.Length - 1;
int max = int.MinValue;
while (i < j)
{
int temp = (j - i) * Math.Min(height[i], height[j]);
if (temp > max)
{
max = temp;
}
if (height[i] < height[j])
{
i++;
}
else
{
j--;
}
}
return max;
}
}
```
---
## 题目06搜索旋转排序数组
> - 题号33
> - 难度:中等
> - https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是`O(log n)`级别。
<b>示例 1</b>:
```c
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
```
<b>示例 2</b>:
```c
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
```
<b>示例 3</b>:
```c
输入: nums = [5,1,3], target = 5
输出: 0
```
<b>示例 4</b>:
```c
输入: nums = [4,5,6,7,8,1,2,3], target = 8
输出: 4
```
<b>示例 5</b>:
```c
输入: nums = [3,1], target = 1
输出: 1
```
**参考代码:**
思路:利用二分法。
- 状态:通过
- 执行用时: 128 ms, 在所有 C# 提交中击败了 97.17% 的用户
- 内存消耗: 23.8 MB, 在所有 C# 提交中击败了 12.00% 的用户
```c
public class Solution
{
public int Search(int[] nums, int target)
{
int i = 0, j = nums.Length - 1;
while (i <= j)
{
int mid = (i + j) / 2;
if (nums[mid] == target)
return mid;
if (nums[mid] >= nums[i])
{
//左半部分有序
if (target > nums[mid])
{
i = mid + 1;
}
else
{
if (target == nums[i])
return i;
if (target > nums[i])
j = mid - 1;
else
i = mid + 1;
}
}
else
{
if (target < nums[mid])
{
j = mid - 1;
}
else
{
if (target == nums[j])
return j;
if (target < nums[j])
i = mid + 1;
else
j = mid - 1;
}
}
}
return -1;
}
}
```
---
## 题目07数组中的第K个最大元素
> - 题号215
> - 难度:中等
> - https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
在未排序的数组中找到第 `k` 个最大的元素。请注意,你需要找的是数组排序后的第 `k` 个最大的元素,而不是第 `k` 个不同的元素。
<b>示例 1</b>:
```c
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
```
<b>示例 2</b>:
```c
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
```
<b>说明</b>:
你可以假设 `k` 总是有效的,且 `1 ≤ k ≤ 数组的长度`
**参考代码:**
思路:利用排序的方法。
- 状态:通过
- 执行用时: 152 ms, 在所有 C# 提交中击败了 76.47% 的用户
- 内存消耗: 24.6 MB, 在所有 C# 提交中击败了 5.55% 的用户
```c
public class Solution
{
public int FindKthLargest(int[] nums, int k)
{
nums = nums.OrderBy(a => a).ToArray();
return nums[nums.Length - k];
}
}
```
---
## 题目08除自身以外数组的乘积
> - 题号238
> - 难度:中等
> - https://leetcode-cn.com/problems/product-of-array-except-self/
给定长度为`n`的整数数组`nums`,其中`n > 1`,返回输出数组`output`,其中`output[i]`等于 `nums`中除`nums[i]`之外其余各元素的乘积。
<b>示例</b>:
```c
输入: [1,2,3,4]
输出: [24,12,8,6]
```
<b>说明</b>: 请不要使用除法,且在`O(n)` 时间复杂度内完成此题。
<b>进阶</b>
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
**参考代码:**
思路:乘积 = 当前数左边的乘积 * 当前数右边的乘积
```c
[1, 2, 3, 4]
左边的乘积 [1, 1, 2, 6]
右边的乘积 [24,12,4, 1]
结果 = 左*右 [24,12,8, 6]
```
- 状态:通过
- 执行用时: 304 ms, 在所有 C# 提交中击败了 100.00% 的用户
- 内存消耗: 34.6 MB, 在所有 C# 提交中击败了 100.00% 的用户
```c
public class Solution
{
public int[] ProductExceptSelf(int[] nums)
{
int len = nums.Length;
int[] output1 = new int[len];//正向乘积
int[] output2 = new int[len];//反向乘积
output1[0] = 1;
output2[len - 1] = 1;
for (int i = 1; i < len; i++)
{
output1[i] = output1[i - 1]*nums[i - 1];
output2[len - i - 1] = output2[len - i]*nums[len - i];
}
for (int i = 0; i < len; i++)
{
output1[i] *= output2[i];
}
return output1;
}
}
```
---
## 题目09寻找两个有序数组的中位数
> - 题号4
> - 难度:困难
> - https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
给定两个大小为`m`和`n`的有序数组`nums1`和`nums2`。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为`O(log(m + n))`。
你可以假设`nums1`和`nums2`不会同时为空。
<b>示例 1</b>:
```c
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
```
<b>示例 2</b>:
```c
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
```
**参考代码:**
思路:利用二分策略。
中位数:用来将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
由于题目要求时间复杂度为`O(log(m + n))`,所以不能从两个有序数组的首尾挨个遍历来找到中位数(复杂度 `O(m + n)`);而是要通过二分策略,通过每次比较,能够直接按比例的刷掉一组数字,最后找到中位数(复杂度`O(log(m + n))`)。
```c
nums1: [a1,a2,a3,...am]
nums2: [b1,b2,b3,...bn]
[nums1[:i],nums2[:j] | nums1[i:], nums2[j:]]
nums1 取 i 个数的左半边
nums2 取 j = (m+n+1)/2 - i 的左半边
```
只要保证左右两边 <b>个数</b> 相同,中位数就在 `|` 这个边界旁边产生,从而可以利用二分法找到合适的`i`。
- 状态:通过
- 执行用时: 160 ms, 在所有 C# 提交中击败了 99.18% 的用户
- 内存消耗: 26.8 MB, 在所有 C# 提交中击败了 5.05% 的用户
```c
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.Length;
int n = nums2.Length;
if (m > n)
return FindMedianSortedArrays(nums2, nums1);
int k = (m + n + 1)/2;
int left = 0;
int right = m;
while (left < right)
{
int i = (left + right)/2;
int j = k - i;
if (nums1[i] < nums2[j - 1])
left = i + 1;
else
right = i;
}
int m1 = left;
int m2 = k - left;
int c1 = Math.Max(m1 == 0 ? int.MinValue : nums1[m1 - 1],
m2 == 0 ? int.MinValue : nums2[m2 - 1]);
if ((m + n)%2 == 1)
return c1;
int c2 = Math.Min(m1 == m ? int.MaxValue : nums1[m1],
m2 == n ? int.MaxValue : nums2[m2]);
return (c1 + c2)*0.5;
}
}
```
---
## 题目10缺失的第一个正数
> - 题号41
> - 难度:困难
> - https://leetcode-cn.com/problems/first-missing-positive/
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
<b>示例1</b>:
```c
输入: [1,2,0]
输出: 3
```
<b>示例2</b>:
```c
输入: [3,4,-1,1]
输出: 2
```
<b>示例3</b>:
```c
输入: [7,8,9,11,12]
输出: 1
```
<b>示例4</b>:
```c
输入: [1,1]
输出: 2
```
<b>实例5</b>:
```c
输入: []
输出: 1
```
<b>说明</b>:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。
**参考代码:**
思路:把数组进行一次“排序”,“排序”的规则是:如果这个数字`i`落在“区间范围里”,`i`就应该放在索引为`i - 1`的位置上。
- 执行结果:通过
- 执行用时100 ms, 在所有 C# 提交中击败了 93.75% 的用户
- 内存消耗24.2 MB, 在所有 C# 提交中击败了 97.44% 的用户
```c
public class Solution {
public int FirstMissingPositive(int[] nums) {
int len = nums.Length;
for (int i = 0; i < len; i++)
{
while (nums[i] != i + 1 && nums[i] <= len && nums[i] > 0 && nums[i] != nums[nums[i] - 1])
{
int temp = nums[i];
nums[i] = nums[temp - 1];
nums[temp - 1] = temp;
}
}
for (int i = 0; i < len; i++)
{
if (nums[i] != i + 1)
{
return i + 1;
}
}
return len + 1; //nums.Length = 0
}
}
```

View File

@ -1,4 +1,4 @@
# 12 数组与稀疏矩阵
# 05 数组与稀疏矩阵
**知识结构:**

View File

@ -1,4 +1,4 @@
# 13 字符串与整数集合
# 06 字符串与整数集合
**知识点:**

View File

@ -1,759 +0,0 @@
# Leetcode同步练习
## 题目01回文数
> - 题号9
> - 难度:简单
> - https://leetcode-cn.com/problems/palindrome-number/
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
<b>示例 1</b>:
```c
输入: 121
输出: true
```
<b>示例 2</b>:
```c
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
```
<b>示例 3</b>:
```c
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
```
**填写代码**
```c
public class Solution
{
public bool IsPalindrome(int x)
{
}
}
```
<b>进阶</b>:
你能不将整数转为字符串来解决这个问题吗?
**参考代码**
- 状态:通过
- 执行用时: 76 ms, 在所有 C# 提交中击败了 98.90% 的用户
- 内存消耗: 14.9 MB, 在所有 C# 提交中击败了 85.12% 的用户
```c
public class Solution {
public bool IsPalindrome(int x) {
if (x < 0)
return false;
int bit = 1;
while (x / bit >= 10)
{
bit = bit * 10;
}
while (x > 0)
{
int left = x % 10;
int right = x / bit;
if (left != right)
{
return false;
}
x = (x % bit) / 10;
bit = bit / 100;
}
return true;
}
```
---
## 题目02x 的平方根
> - 题号69
> - 难度:简单
> - https://leetcode-cn.com/problems/sqrtx/
实现 `int sqrt(int x)` 函数。
计算并返回`x`的平方根,其中`x`是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
<b>示例 1</b>:
```c
输入: 4
输出: 2
```
<b>示例 2</b>:
```c
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
```
**思路**:利用牛顿迭代法。
![牛顿迭代公式](https://img-blog.csdnimg.cn/2019082111485172.png)
**参考代码**
- 状态:通过
- 执行用时: 48 ms, 在所有 C# 提交中击败了 100.00% 的用户
- 内存消耗: 13.7 MB, 在所有 C# 提交中击败了 5.40% 的用户
```c
public class Solution {
public int MySqrt(int x) {
if (x < 0)
throw new ArgumentOutOfRangeException();
double error = 1.0e-5;
double cur = x;
while (Math.Abs(cur*cur - x) > error)
{
cur = (cur + 1.0*x/cur)/2.0;
}
return (int)cur;
}
}
```
---
## 题目03爬楼梯
> - 题号70
> - 难度:简单
> - https://leetcode-cn.com/problems/climbing-stairs/
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
<b>注意</b>:给定 n 是一个正整数。
<b>示例 1</b>
```c
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
```
<b>示例 2</b>
```c
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
```
<b>示例 3</b>
```c
输入: 44
输出: 1134903170
```
**思路**:利用循环
分析这个题目:
- 1 阶f(1) = 1 种方案
- 2 阶f(2) = 2 种方案
- 3 阶f(3) = 3 种方案
- 4 阶f(4) = 5 种方案
- ……
- n 阶f(n) = f(n-1) + f(n-2) 种方案
即,该问题可以转换为斐波那契数列问题。
**参考代码**
- 状态:通过
- 执行用时: 52 ms, 在所有 C# 提交中击败了 97.87% 的用户
- 内存消耗: 13.7 MB, 在所有 C# 提交中击败了 5.98% 的用户
```c
public class Solution {
public int ClimbStairs(int n) {
if (n <= 2)
return n;
int first = 1;
int second = 2;
int result = 0;
for (int i = 3; i <= n; i++)
{
result = first + second;
first = second;
second = result;
}
return result;
}
}
```
---
## 题目04买卖股票的最佳时机
> - 题号121
> - 难度:简单
> - https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
<b>示例 1</b>:
```c
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1的时候买入在第 5 天(股票价格 = 6的时候卖出最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
```
<b>示例 2</b>:
```c
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
```
**思路**:如果今天把股票卖掉能够赚最多钱的最大值,即为最大利润。
**参考代码**
- 状态:通过
- 执行用时: 132 ms, 在所有 C# 提交中击败了 97.33% 的用户
- 内存消耗: 24 MB, 在所有 C# 提交中击败了 5.62% 的用户
```c
public class Solution
{
public int MaxProfit(int[] prices)
{
if (prices.Length <= 1)
return 0;
int min = prices[0];
int max = 0;
for (int i = 1; i < prices.Length; i++)
{
int earn = prices[i] - min;
if (earn > max)
{
max = earn;
}
if (prices[i] < min)
{
min = prices[i];
}
}
return max;
}
}
```
---
## 题目05买卖股票的最佳时机 II
> - 题号122
> - 难度:简单
> - https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
<b>注意</b>:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
<b>示例 1</b>:
```c
输入: [7,1,5,3,6,4]
输出: 7
解释:
在第 2 天(股票价格 = 1的时候买入在第 3 天(股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3的时候买入在第 5 天(股票价格 = 6的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
```
<b>示例 2</b>:
```c
输入: [1,2,3,4,5]
输出: 4
解释:
在第 1 天(股票价格 = 1的时候买入在第 5 天 (股票价格 = 5的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
```
<b>示例 3</b>:
```c
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
```
**思路**:贪心算法
贪心策略:只要后一天价格比前一天高,就在前一天买进后一天卖出。
![有升有降的情况](https://img-blog.csdnimg.cn/20190914100650406.png)
![连续上升的情况](https://img-blog.csdnimg.cn/20200325110545912.png)
**参考代码**
- 状态:通过
- 执行用时: 140 ms, 在所有 C# 提交中击败了 72.02% 的用户
- 内存消耗: 24.2 MB, 在所有 C# 提交中击败了 5.36% 的用户
```c
public class Solution
{
public int MaxProfit(int[] prices)
{
int earn = 0;
for (int i = 0; i < prices.Length-1; i++)
{
earn += Math.Max(prices[i + 1] - prices[i], 0);
}
return earn;
}
}
```
---
## 题目06跳跃游戏
> - 题号55
> - 难度:中等
> - https://leetcode-cn.com/problems/jump-game/
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
**示例 1:**
```c
输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3
步到达最后一个位置。
```
**示例 2:**
```c
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0
所以你永远不可能到达最后一个位置。
```
**示例 3:**
```c
输入:[0]
输出true
```
**思路:贪心算法**
贪心策略每次记录能跳到点的最大值如果当前点超出最大值返回false如果最大值达到最后一个位置返回true。
**参考代码:**
- 执行结果:通过
- 执行用时120 ms, 在所有 C# 提交中击败了 57.32% 的用户
- 内存消耗26.2 MB, 在所有 C# 提交中击败了 6.67% 的用户
```c
public class Solution
{
public bool CanJump(int[] nums)
{
int maxlength = 0; //记录所能到达的最远点
for (int i = 0; maxlength < nums.Length-1; i++)
{
if (i > maxlength)
{
return false;//若此点已不能到达返回false
}
maxlength = Math.Max(i + nums[i], maxlength);
}
return true;
}
}
```
---
## 题目07三数之和
> - 题号15
> - 难度:中等
> - https://leetcode-cn.com/problems/3sum/
给定一个包含`n`个整数的数组`nums`,判断`nums`中是否存在三个元素`abc`,使得`a + b + c = 0`?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
**示例:**
```c
给定数组 nums = [-1, 0, 1, 2, -1, -4]
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
```
**思路:利用 排序 + 三索引 的方法。**
为了避免三次循环,提升执行效率。首先,对`nums`进行排序。然后固定3个索引`i,l(left),r(right)``i`进行最外层循环,`l`指向`nums[i]`之后数组的最小值,`r`指向`nums[i]`之后数组的最大值。模仿快速排序的思路,如果`nums[i] > 0`就不需要继续计算了,否则计算`nums[i] + nums[l] + nums[r]`是否等于零并进行相应的处理。如果大于零,向`l`方向移动`r`指针,如果小于零,向`r`方向移动`l`索引如果等于零则加入到存储最后结果的result链表中。当然题目中要求这个三元组不可重复所以在进行的过程中加入去重就好。
**参考代码:**
- 执行结果:通过
- 执行用时348 ms, 在所有 C# 提交中击败了 99.54% 的用户
- 内存消耗35.8 MB, 在所有 C# 提交中击败了 6.63% 的用户
```c
public class Solution
{
public IList<IList<int>> ThreeSum(int[] nums)
{
IList<IList<int>> result = new List<IList<int>>();
nums = nums.OrderBy(a => a).ToArray();
int len = nums.Length;
for (int i = 0; i < len - 2; i++)
{
if (nums[i] > 0)
break; // 如果最小的数字大于0, 后面的操作已经没有意义
if (i > 0 && nums[i - 1] == nums[i])
continue; // 跳过三元组中第一个元素的重复数据
int l = i + 1;
int r = len - 1;
while (l < r)
{
int sum = nums[i] + nums[l] + nums[r];
if (sum < 0)
{
l++;
}
else if (sum > 0)
{
r--;
}
else
{
result.Add(new List<int>() {nums[i], nums[l], nums[r]});
// 跳过三元组中第二个元素的重复数据
while (l < r && nums[l] == nums[l + 1])
{
l++;
}
// 跳过三元组中第三个元素的重复数据
while (l < r && nums[r - 1] == nums[r])
{
r--;
}
l++;
r--;
}
}
}
return result;
}
}
```
---
## 题目08最接近的三数之和
> - 题号16
> - 难度:中等
> - https://leetcode-cn.com/problems/3sum-closest/
给定一个包括`n`个整数的数组`nums`和一个目标值`target`。找出`nums`中的三个整数,使得它们的和与`target`最接近。返回这三个数的和。假定每组输入只存在唯一答案。
<b>示例</b> :
```c
例如,给定数组 nums = [-121-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
```
<b>思路:利用 排序 + 三索引 的方法</b>
**参考代码:**
- 状态:通过
- 执行用时: 132 ms, 在所有 C# 提交中击败了 100.00% 的用户
- 内存消耗: 24 MB, 在所有 C# 提交中击败了 5.55% 的用户
```c
public class Solution
{
public int ThreeSumClosest(int[] nums, int target)
{
nums = nums.OrderBy(a => a).ToArray();
int result = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.Length - 2; i++)
{
int start = i + 1, end = nums.Length - 1;
while (start < end)
{
int sum = nums[start] + nums[end] + nums[i];
if (Math.Abs(target - sum) < Math.Abs(target - result))
result = sum;
if (sum > target)
end--;
else if (sum < target)
start++;
else
return result;
}
}
return result;
}
}
```
---
## 题目09螺旋矩阵 II
> - 题号59
> - 难度:中等
> - https://leetcode-cn.com/problems/spiral-matrix-ii/
给定一个正整数 n生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
<b>示例</b>:
```c
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
```
**参考代码**
- 状态:通过
- 执行用时: 296 ms, 在所有 C# 提交中击败了 97.67% 的用户
- 内存消耗: 25 MB, 在所有 C# 提交中击败了 11.11% 的用户
```c
public class Solution
{
public int[][] GenerateMatrix(int n)
{
int[][] matrix = new int[n][];
for (int i = 0; i < n; i++)
{
matrix[i] = new int[n];
}
int start = 0;//起始位置
int end1 = n - 1;//最左边位置
int end2 = n - 1;//最下边位置
int count = 1;
while (start < end1 && start < end2)
{
LeftToRight(start, end1, start, matrix, ref count);
TopToBottom(start + 1, end2, end1, matrix, ref count);
RightToLeft(end1 - 1, start, end2, matrix, ref count);
BottomToTop(end2 - 1, start + 1, start, matrix, ref count);
start++;
end1 = n - 1 - start;
end2 = n - 1 - start;
}
if (n%2 == 1)
{
matrix[start][start] = count;
}
return matrix;
}
private void LeftToRight(int start, int end, int rowIndex, int[][] matrix, ref int from)
{
for (int i = start; i <= end; i++)
{
matrix[rowIndex][i] = from;
from++;
}
}
private void TopToBottom(int start, int end, int colIndex, int[][] matrix, ref int from)
{
for (int i = start; i <= end; i++)
{
matrix[i][colIndex] = from;
from++;
}
}
private void RightToLeft(int start, int end, int rowIndex, int[][] matrix, ref int from)
{
for (int i = start; i >= end; i--)
{
matrix[rowIndex][i] = from;
from++;
}
}
private void BottomToTop(int start, int end, int colIndex, int[][] matrix, ref int from)
{
for (int i = start; i >= end; i--)
{
matrix[i][colIndex] = from;
from++;
}
}
}
```
## 题目10不同路径
> - 题号62
> - 难度:中等
> - https://leetcode-cn.com/problems/unique-paths/
一个机器人位于一个 m x n 网格的左上角 起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角在下图中标记为“Finish”
问总共有多少条不同的路径?
![问题](https://img-blog.csdnimg.cn/20190912160514978.png)
例如上图是一个7 x 3 的网格。有多少可能的路径?
<b>说明</b>m 和 n 的值均不超过 100。
<b>示例 1</b>:
```c
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
```
<b>示例 2</b>:
```c
输入: m = 7, n = 3
输出: 28
```
<b>示例 3</b>:
```c
输入: m = 23, n = 12
输出: 193536720
```
<b>思路:</b>利用动态规划。
动态规划表格01
![表01](https://img-blog.csdnimg.cn/20190912160347481.png)
动态规划表格02
![表02](https://img-blog.csdnimg.cn/20190912160424714.png)
动态规划的最优子结构为:`d[i,j] = d[i-1,j] + d[i,j-1]`
- 状态:通过
- 62 / 62 个通过测试用例
- 执行用时: 52 ms, 在所有 C# 提交中击败了 93.18% 的用户
- 内存消耗: 13.6 MB, 在所有 C# 提交中击败了 17.65% 的用户
```c
public class Solution
{
public int UniquePaths(int m, int n)
{
int[,] memo = new int[m, n];
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == 0)
{
memo[i, j] = 1;
}
else if (j == 0)
{
memo[i, j] = 1;
}
else
{
memo[i, j] = memo[i - 1, j] + memo[i, j - 1];
}
}
}
return memo[m - 1, n - 1];
}
}
```

View File

@ -1,5 +1,5 @@
# 15
# 07
**知识结构:**

View File

@ -1,794 +0,0 @@
# Leetcode同步练习
## 题目01合并两个有序链表
> - 题号21
> - 难度:简单
> - https://leetcode-cn.com/problems/merge-two-sorted-lists/
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
**示例:**
```c
输入1->2->4, 1->3->4
输出1->1->2->3->4->4
```
**参考代码**
- 执行结果:通过
- 执行用时108 ms, 在所有 C# 提交中击败了 83.80% 的用户
- 内存消耗25.9 MB, 在所有 C# 提交中击败了 5.85% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode MergeTwoLists(ListNode l1, ListNode l2)
{
ListNode pHead = new ListNode(int.MaxValue);
ListNode temp = pHead;
while (l1 != null && l2 != null)
{
if (l1.val < l2.val)
{
temp.next = l1;
l1 = l1.next;
}
else
{
temp.next = l2;
l2 = l2.next;
}
temp = temp.next;
}
if (l1 != null)
temp.next = l1;
if (l2 != null)
temp.next = l2;
return pHead.next;
}
}
```
---
## 题目02删除排序链表中的重复元素
> - 题号83
> - 难度:简单
> - https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
**示例 1:**
```c
输入: 1->1->2
输出: 1->2
```
**示例 2:**
```c
输入: 1->1->2->3->3
输出: 1->2->3
```
**思路**:利用双指针的方式。
`p1`作为前面的指针探路,`p2`作为后面的指针跟进,如果遇到重复元素,`p2.next`跳过去,`p1`跑完整个链表所有重复元素都被摘下来。
**参考代码**
- 执行结果:通过
- 执行用时160 ms, 在所有 C# 提交中击败了 5.23% 的用户
- 内存消耗25.9 MB, 在所有 C# 提交中击败了 5.72% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode DeleteDuplicates(ListNode head)
{
if (head == null)
return head;
ListNode p1 = head.next;
ListNode p2 = head;
while (p1 != null)
{
if (p1.val == p2.val)
p2.next = p1.next;
else
p2 = p2.next;
p1 = p1.next;
}
return head;
}
}
```
---
## 题目03环形链表
> - 题号141
> - 难度:简单
> - https://leetcode-cn.com/problems/linked-list-cycle/
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数`pos` 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果`pos`是 -1则在该链表中没有环。
<b>示例 1</b>
```c
输入head = [3,2,0,-4], pos = 1
输出true
解释:链表中有一个环,其尾部连接到第二个节点。
```
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hc3NldHMubGVldGNvZGUtY24uY29tL2FsaXl1bi1sYy11cGxvYWQvdXBsb2Fkcy8yMDE4LzEyLzA3L2NpcmN1bGFybGlua2VkbGlzdC5wbmc)
<b>示例 2</b>
```c
输入head = [1,2], pos = 0
输出true
解释:链表中有一个环,其尾部连接到第一个节点。
```
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hc3NldHMubGVldGNvZGUtY24uY29tL2FsaXl1bi1sYy11cGxvYWQvdXBsb2Fkcy8yMDE4LzEyLzA3L2NpcmN1bGFybGlua2VkbGlzdF90ZXN0Mi5wbmc)
<b>示例 3</b>
```c
输入head = [1], pos = -1
输出false
解释:链表中没有环。
```
![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hc3NldHMubGVldGNvZGUtY24uY29tL2FsaXl1bi1sYy11cGxvYWQvdXBsb2Fkcy8yMDE4LzEyLzA3L2NpcmN1bGFybGlua2VkbGlzdF90ZXN0My5wbmc)
<b>进阶</b>
你能用 O(1)(即,常量)内存解决此问题吗?
**思路**:利用双指针的方式。
通常情况下,判断是否包含了重复的元素,我们使用`Hash`的方式来做。对于单链表的这种场景,我们也可以使用双指针的方式。
第一个指针 `p1` 每次移动两个节点,第二个指针 `p2` 每次移动一个节点,如果该链表存在环的话,第一个指针一定会再次碰到第二个指针,反之,则不存在环。
比如:`head = [1,2,3,4,5]`,奇数
```c
p11 3 5 2 4 1
p21 2 3 4 5 1
```
比如:`head = [1,2,3,4]`,偶数
```c
p11 3 1 3 1
p21 2 3 4 1
```
**参考代码**
- 状态:通过
- 执行用时: 112 ms, 在所有 C# 提交中击败了 98.43% 的用户
- 内存消耗: 24.9 MB, 在所有 C# 提交中击败了 5.13% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public bool HasCycle(ListNode head) {
ListNode p1 = head;
ListNode p2 = head;
while (p1 != null && p1.next != null)
{
p1 = p1.next.next;
p2 = p2.next;
if (p1 == p2)
return true;
}
return false;
}
}
```
## 题目04反转链表
> - 题号206
> - 难度:简单
> - https://leetcode-cn.com/problems/reverse-linked-list/
反转一个单链表。
<b>示例</b>:
```c
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
```
<b>进阶</b>:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
**思路**:利用双指针的方式。
`p1`作为前面的指针探路,`p2`作为后面的指针跟进,顺着链表跑一圈,搞定问题。
**参考代码**
- 状态:通过
- 执行用时: 116 ms, 在所有 C# 提交中击败了 97.50% 的用户
- 内存消耗: 23.3 MB, 在所有 C# 提交中击败了 5.26% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode ReverseList(ListNode head)
{
if (head == null || head.next == null)
return head;
ListNode p1 = head;
ListNode p2 = null;
while (p1 != null)
{
ListNode temp = p1.next;
p1.next = p2;
p2 = p1;
p1 = temp;
}
return p2;
}
}
```
---
## 题目05删除链表中的节点
> - 题号237
> - 难度:简单
> - https://leetcode-cn.com/problems/delete-node-in-a-linked-list/
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:
![](https://img-blog.csdnimg.cn/20190920111622847.png)
<b>示例 1</b>:
```c
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
```
<b>示例 2</b>:
```c
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
```
<b>说明</b>:
- 链表至少包含两个节点。
- 链表中所有节点的值都是唯一的。
- 给定的节点为非末尾节点并且一定是链表中的一个有效节点。
- 不要从你的函数中返回任何结果。
**思路:** 这道题没有给出链表的头节点,而是直接给出要删除的节点,让我们进行原地删除。我们对于该节点的前一个节点一无所知,所以无法直接执行删除操作。因此,我们将要删除节点的 next 节点的值赋值给要删除的节点,转而去删除 next 节点,从而达成目的。
**参考代码**
- 状态:通过
- 41 / 41 个通过测试用例
- 执行用时: 120 ms, 在所有 C# 提交中击败了 99.55% 的用户
- 内存消耗: 24.4 MB, 在所有 C# 提交中击败了 5.88% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public void DeleteNode(ListNode node)
{
ListNode temp = node.next;
while (temp != null)
{
node.val = temp.val;
temp = temp.next;
if (temp != null)
{
node = node.next;
}
}
node.next = null;
}
}
```
---
## 题目06两数相加
> - 题号2
> - 难度:中等
> - https://leetcode-cn.com/problems/add-two-numbers/
给出两个 <b>非空</b> 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 <b>逆序</b> 的方式存储的,并且它们的每个节点只能存储 <b>一位</b> 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
<b>示例 1</b>
```c
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出7 -> 0 -> 8
原因342 + 465 = 807
```
<b>示例 2</b>
```c
输入:(3 -> 7) + (9 -> 2)
输出2 -> 0 -> 1
原因73 + 29 = 102
```
**思路**:模仿我们小学时代学的加法运算。个位相加超过十进一,十位相加有进位则加上进位,依次类推。
<b>参考代码:</b>
- 状态:通过
- 执行用时: 144 ms, 在所有 C# 提交中击败了 97.98% 的用户
- 内存消耗: 26.7 MB, 在所有 C# 提交中击败了 5.07% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode AddTwoNumbers(ListNode l1, ListNode l2)
{
ListNode result = new ListNode(-1);
ListNode l3 = result;
int flag = 0;
while (l1 != null && l2 != null)
{
int a = l1.val;
int b = l2.val;
int c = a + b + flag;
l3.next = new ListNode(c%10);
flag = c >= 10 ? 1 : 0;
l1 = l1.next;
l2 = l2.next;
l3 = l3.next;
}
while (l1 != null)
{
int a = l1.val + flag;
l3.next = new ListNode(a%10);
flag = a >= 10 ? 1 : 0;
l1 = l1.next;
l3 = l3.next;
}
while (l2 != null)
{
int b = l2.val + flag;
l3.next = new ListNode(b%10);
flag = b >= 10 ? 1 : 0;
l2 = l2.next;
l3 = l3.next;
}
if (flag == 1)
{
l3.next = new ListNode(flag);
}
return result.next;
}
}
```
---
## 题目07删除链表的倒数第N个节点
> - 题号19
> - 难度:中等
> - https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
给定一个链表,删除链表的倒数第`n`个节点,并且返回链表的头结点。
**示例**
```c
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
```
**说明**
给定的`n`保证是有效的。
**进阶**
你能尝试使用一趟扫描实现吗?
**思路:** 使用两个指针,前面的指针`p1`先走`n`步,接着让后面的指针`p2`与`p1`同步走,`p1`走到终点,`p2`即走到要移除的结点位置。
**参考代码:**
- 执行结果:通过
- 执行用时104 ms, 在所有 C# 提交中击败了 86.93% 的用户
- 内存消耗24.6 MB, 在所有 C# 提交中击败了 100.00% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode RemoveNthFromEnd(ListNode head, int n)
{
ListNode p1 = head;
ListNode p2 = head;
while (n > 0)
{
p1 = p1.next;
n--;
}
if (p1 == null) //移除头结点
{
return head.next;
}
while (p1.next != null)
{
p1 = p1.next;
p2 = p2.next;
}
p2.next = p2.next.next;
return head;
}
}
```
---
## 题目08两两交换链表中的节点
> - 题号24
> - 难度:中等
> - https://leetcode-cn.com/problems/swap-nodes-in-pairs/
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
**你不能只是单纯的改变节点内部的值**,而是需要实际的进行节点交换。
**示例:**
> 给定 1->2->3->4, 你应该返回 2->1->4->3.
**参考代码**
- 执行结果:通过
- 执行用时100 ms, 在所有 C# 提交中击败了 93.18% 的用户
- 内存消耗23.4 MB, 在所有 C# 提交中击败了 87.72% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode SwapPairs(ListNode head)
{
if (head == null || head.next == null)
return head;
head = Swap(head);
ListNode temp = head.next;
while (temp != null && temp.next != null)
{
temp.next = Swap(temp.next);
if (temp.next != null)
{
temp = temp.next.next;
}
}
return head;
}
public ListNode Swap(ListNode node)
{
if (node == null || node.next == null)
return node;
ListNode t = node.next;
node.next = t.next;
t.next = node;
return t;
}
}
```
---
## 题目09旋转链表
> - 题号61
> - 难度:中等
> - https://leetcode-cn.com/problems/rotate-list/
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
**示例 1:**
```c
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
```
**示例 2:**
```c
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
```
**参考代码**
- 执行结果:通过
- 执行用时100 ms, 在所有 C# 提交中击败了 98.13% 的用户
- 内存消耗25.1 MB, 在所有 C# 提交中击败了 100.00% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode RotateRight(ListNode head, int k)
{
if (head == null || k == 0)
return head;
int len = GetLength(head);
int index = len - k%len;
if (index == len)
return head;
ListNode temp1 = head;
ListNode temp2 = head;
for (int i = 0; i < index - 1; i++)
{
temp1 = temp1.next;
}
head = temp1.next;
temp1.next = null;
temp1 = head;
while (temp1.next != null)
{
temp1 = temp1.next;
}
temp1.next = temp2;
return head;
}
public int GetLength(ListNode head)
{
ListNode temp = head;
int i = 0;
while (temp != null)
{
i++;
temp = temp.next;
}
return i;
}
}
```
---
## 题目10合并K个排序链表
> - 题号23
> - 难度:困难
> - https://leetcode-cn.com/problems/merge-k-sorted-lists/
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
<b>示例</b>:
```c
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
```
<b>思路:</b>两两合并的方式。
构造合并两个有序链表得到一个新的有序链表的方法:`ListNode MergeTwoLists(ListNode l1, ListNode l2)`。可以使用该方法合并前两个有序链表得到一个新的有序链表,之后把这个新链表与第三个有序链表合并,依次类推,最后得到合并`K`个有序列表的新列表。
**参考代码**
- 执行结果:通过
- 执行用时256 ms, 在所有 C# 提交中击败了 36.69% 的用户
- 内存消耗29.3 MB, 在所有 C# 提交中击败了 18.37% 的用户
```c
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int x) { val = x; }
* }
*/
public class Solution
{
public ListNode MergeTwoLists(ListNode l1, ListNode l2)
{
ListNode pHead = new ListNode(int.MaxValue);
ListNode temp = pHead;
while (l1 != null && l2 != null)
{
if (l1.val < l2.val)
{
temp.next = l1;
l1 = l1.next;
}
else
{
temp.next = l2;
l2 = l2.next;
}
temp = temp.next;
}
if (l1 != null)
temp.next = l1;
if (l2 != null)
temp.next = l2;
return pHead.next;
}
public ListNode MergeKLists(ListNode[] lists) {
if (lists.Length == 0)
return null;
ListNode result = lists[0];
for (int i = 1; i < lists.Length; i++)
{
result = MergeTwoLists(result, lists[i]);
}
return result;
}
}
```

View File

@ -1,5 +1,5 @@
# 17 ͼ
# 08 ͼ
**知识结构:**

View File

@ -1,4 +1,4 @@
# 19 排序
# 09 排序
**知识结构:**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff