mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 08:50:15 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -207,18 +207,16 @@ function twoSum(array $nums, int $target): array
|
||||
Swift:
|
||||
```swift
|
||||
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
|
||||
var res = [Int]()
|
||||
var dict = [Int : Int]()
|
||||
for i in 0 ..< nums.count {
|
||||
let other = target - nums[i]
|
||||
if dict.keys.contains(other) {
|
||||
res.append(i)
|
||||
res.append(dict[other]!)
|
||||
return res
|
||||
// 值: 下标
|
||||
var map = [Int: Int]()
|
||||
for (i, e) in nums.enumerated() {
|
||||
if let v = map[target - e] {
|
||||
return [v, i]
|
||||
} else {
|
||||
map[e] = i
|
||||
}
|
||||
dict[nums[i]] = i
|
||||
}
|
||||
return res
|
||||
return []
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -197,7 +197,23 @@ var removeElement = (nums, val) => {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function removeElement(nums: number[], val: number): number {
|
||||
let slowIndex: number = 0, fastIndex: number = 0;
|
||||
while (fastIndex < nums.length) {
|
||||
if (nums[fastIndex] !== val) {
|
||||
nums[slowIndex++] = nums[fastIndex];
|
||||
}
|
||||
fastIndex++;
|
||||
}
|
||||
return slowIndex;
|
||||
};
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
def remove_element(nums, val)
|
||||
i = 0
|
||||
|
@ -649,6 +649,41 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
```Java
|
||||
class Solution {
|
||||
//前缀表(不减一)Java实现
|
||||
public int strStr(String haystack, String needle) {
|
||||
if (needle.length() == 0) return 0;
|
||||
int[] next = new int[needle.length()];
|
||||
getNext(next, needle);
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < haystack.length(); i++) {
|
||||
while (j > 0 && needle.charAt(j) != haystack.charAt(i))
|
||||
j = next[j - 1];
|
||||
if (needle.charAt(j) == haystack.charAt(i))
|
||||
j++;
|
||||
if (j == needle.length())
|
||||
return i - needle.length() + 1;
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
private void getNext(int[] next, String s) {
|
||||
int j = 0;
|
||||
next[0] = 0;
|
||||
for (int i = 1; i < s.length(); i++) {
|
||||
while (j > 0 && s.charAt(j) != s.charAt(i))
|
||||
j = next[j - 1];
|
||||
if (s.charAt(j) == s.charAt(i))
|
||||
j++;
|
||||
next[i] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python3:
|
||||
|
||||
```python
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
// 到这里了说明整个数组都是倒叙了,反转一下便可
|
||||
// 到这里了说明整个数组都是倒序了,反转一下便可
|
||||
reverse(nums.begin(), nums.end());
|
||||
}
|
||||
};
|
||||
|
@ -255,6 +255,7 @@ public:
|
||||
|
||||
|
||||
## Java
|
||||
**使用标记数组**
|
||||
```Java
|
||||
class Solution {
|
||||
List<List<Integer>> lists = new ArrayList<>();
|
||||
@ -292,6 +293,44 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
**不使用标记数组**
|
||||
```Java
|
||||
class Solution {
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
LinkedList<Integer> path = new LinkedList<>();
|
||||
int sum = 0;
|
||||
|
||||
public List<List<Integer>> combinationSum2( int[] candidates, int target ) {
|
||||
//为了将重复的数字都放到一起,所以先进行排序
|
||||
Arrays.sort( candidates );
|
||||
backTracking( candidates, target, 0 );
|
||||
return res;
|
||||
}
|
||||
|
||||
private void backTracking( int[] candidates, int target, int start ) {
|
||||
if ( sum == target ) {
|
||||
res.add( new ArrayList<>( path ) );
|
||||
return;
|
||||
}
|
||||
for ( int i = start; i < candidates.length && sum + candidates[i] <= target; i++ ) {
|
||||
//正确剔除重复解的办法
|
||||
//跳过同一树层使用过的元素
|
||||
if ( i > start && candidates[i] == candidates[i - 1] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sum += candidates[i];
|
||||
path.add( candidates[i] );
|
||||
// i+1 代表当前组内元素只选取一次
|
||||
backTracking( candidates, target, i + 1 );
|
||||
|
||||
int temp = path.getLast();
|
||||
sum -= temp;
|
||||
path.removeLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
**回溯+巧妙去重(省去使用used**
|
||||
@ -384,6 +423,7 @@ class Solution:
|
||||
## Go
|
||||
主要在于如何在回溯中去重
|
||||
|
||||
**使用used数组**
|
||||
```go
|
||||
func combinationSum2(candidates []int, target int) [][]int {
|
||||
var trcak []int
|
||||
@ -423,7 +463,41 @@ func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**不使用used数组**
|
||||
```go
|
||||
func combinationSum2(candidates []int, target int) [][]int {
|
||||
var trcak []int
|
||||
var res [][]int
|
||||
sort.Ints(candidates)
|
||||
backtracking(0,0,target,candidates,trcak,&res)
|
||||
return res
|
||||
}
|
||||
func backtracking(startIndex,sum,target int,candidates,trcak []int,res *[][]int){
|
||||
//终止条件
|
||||
if sum==target{
|
||||
tmp:=make([]int,len(trcak))
|
||||
//拷贝
|
||||
copy(tmp,trcak)
|
||||
//放入结果集
|
||||
*res=append(*res,tmp)
|
||||
return
|
||||
}
|
||||
//回溯
|
||||
for i:=startIndex;i<len(candidates) && sum+candidates[i]<=target;i++{
|
||||
// 若当前树层有使用过相同的元素,则跳过
|
||||
if i>startIndex&&candidates[i]==candidates[i-1]{
|
||||
continue
|
||||
}
|
||||
//更新路径集合和sum
|
||||
trcak=append(trcak,candidates[i])
|
||||
sum+=candidates[i]
|
||||
backtracking(i+1,sum,target,candidates,trcak,res)
|
||||
//回溯
|
||||
trcak=trcak[:len(trcak)-1]
|
||||
sum-=candidates[i]
|
||||
}
|
||||
}
|
||||
```
|
||||
## javaScript
|
||||
|
||||
```js
|
||||
|
@ -323,5 +323,76 @@ func permuteUnique(_ nums: [Int]) -> [[Int]] {
|
||||
}
|
||||
```
|
||||
|
||||
### C
|
||||
```c
|
||||
//临时数组
|
||||
int *path;
|
||||
//返回数组
|
||||
int **ans;
|
||||
int *used;
|
||||
int pathTop, ansTop;
|
||||
|
||||
//拷贝path到ans中
|
||||
void copyPath() {
|
||||
int *tempPath = (int*)malloc(sizeof(int) * pathTop);
|
||||
int i;
|
||||
for(i = 0; i < pathTop; ++i) {
|
||||
tempPath[i] = path[i];
|
||||
}
|
||||
ans[ansTop++] = tempPath;
|
||||
}
|
||||
|
||||
void backTracking(int* used, int *nums, int numsSize) {
|
||||
//若path中元素个数等于numsSize,将path拷贝入ans数组中
|
||||
if(pathTop == numsSize)
|
||||
copyPath();
|
||||
int i;
|
||||
for(i = 0; i < numsSize; i++) {
|
||||
//若当前元素已被使用
|
||||
//或前一位元素与当前元素值相同但并未被使用
|
||||
//则跳过此分支
|
||||
if(used[i] || (i != 0 && nums[i] == nums[i-1] && used[i-1] == 0))
|
||||
continue;
|
||||
|
||||
//将当前元素的使用情况设为True
|
||||
used[i] = 1;
|
||||
path[pathTop++] = nums[i];
|
||||
backTracking(used, nums, numsSize);
|
||||
used[i] = 0;
|
||||
--pathTop;
|
||||
}
|
||||
}
|
||||
|
||||
int cmp(void* elem1, void* elem2) {
|
||||
return *((int*)elem1) - *((int*)elem2);
|
||||
}
|
||||
|
||||
int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
|
||||
//排序数组
|
||||
qsort(nums, numsSize, sizeof(int), cmp);
|
||||
//初始化辅助变量
|
||||
pathTop = ansTop = 0;
|
||||
path = (int*)malloc(sizeof(int) * numsSize);
|
||||
ans = (int**)malloc(sizeof(int*) * 1000);
|
||||
//初始化used辅助数组
|
||||
used = (int*)malloc(sizeof(int) * numsSize);
|
||||
int i;
|
||||
for(i = 0; i < numsSize; i++) {
|
||||
used[i] = 0;
|
||||
}
|
||||
|
||||
backTracking(used, nums, numsSize);
|
||||
|
||||
//设置返回的数组的长度
|
||||
*returnSize = ansTop;
|
||||
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
|
||||
int z;
|
||||
for(z = 0; z < ansTop; z++) {
|
||||
(*returnColumnSizes)[z] = numsSize;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -166,7 +166,7 @@ if (i > startIndex && nums[i] == nums[i - 1] ) {
|
||||
|
||||
|
||||
### Java
|
||||
|
||||
使用used数组
|
||||
```java
|
||||
class Solution {
|
||||
List<List<Integer>> result = new ArrayList<>();// 存放符合条件结果的集合
|
||||
@ -202,6 +202,37 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
不使用used数组
|
||||
```java
|
||||
class Solution {
|
||||
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
LinkedList<Integer> path = new LinkedList<>();
|
||||
|
||||
public List<List<Integer>> subsetsWithDup( int[] nums ) {
|
||||
Arrays.sort( nums );
|
||||
subsetsWithDupHelper( nums, 0 );
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
private void subsetsWithDupHelper( int[] nums, int start ) {
|
||||
res.add( new ArrayList<>( path ) );
|
||||
|
||||
for ( int i = start; i < nums.length; i++ ) {
|
||||
// 跳过当前树层使用过的、相同的元素
|
||||
if ( i > start && nums[i - 1] == nums[i] ) {
|
||||
continue;
|
||||
}
|
||||
path.add( nums[i] );
|
||||
subsetsWithDupHelper( nums, i + 1 );
|
||||
path.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Python
|
||||
```python
|
||||
class Solution:
|
||||
|
@ -574,7 +574,87 @@ var isSymmetric = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
## Swift:
|
||||
|
||||
> 递归
|
||||
```swift
|
||||
func isSymmetric(_ root: TreeNode?) -> Bool {
|
||||
return _isSymmetric(root?.left, right: root?.right)
|
||||
}
|
||||
func _isSymmetric(_ left: TreeNode?, right: TreeNode?) -> Bool {
|
||||
// 首先排除空节点情况
|
||||
if left == nil && right == nil {
|
||||
return true
|
||||
} else if left == nil && right != nil {
|
||||
return false
|
||||
} else if left != nil && right == nil {
|
||||
return false
|
||||
} else if left!.val != right!.val {
|
||||
// 进而排除数值不相等的情况
|
||||
return false
|
||||
}
|
||||
|
||||
// left 和 right 都不为空, 且数值也相等就递归
|
||||
let inSide = _isSymmetric(left!.right, right: right!.left)
|
||||
let outSide = _isSymmetric(left!.left, right: right!.right)
|
||||
return inSide && outSide
|
||||
}
|
||||
```
|
||||
|
||||
> 迭代 - 使用队列
|
||||
```swift
|
||||
func isSymmetric2(_ root: TreeNode?) -> Bool {
|
||||
guard let root = root else {
|
||||
return true
|
||||
}
|
||||
var queue = [TreeNode?]()
|
||||
queue.append(root.left)
|
||||
queue.append(root.right)
|
||||
while !queue.isEmpty {
|
||||
let left = queue.removeFirst()
|
||||
let right = queue.removeFirst()
|
||||
if left == nil && right == nil {
|
||||
continue
|
||||
}
|
||||
if left == nil || right == nil || left?.val != right?.val {
|
||||
return false
|
||||
}
|
||||
queue.append(left!.left)
|
||||
queue.append(right!.right)
|
||||
queue.append(left!.right)
|
||||
queue.append(right!.left)
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
> 迭代 - 使用栈
|
||||
```swift
|
||||
func isSymmetric3(_ root: TreeNode?) -> Bool {
|
||||
guard let root = root else {
|
||||
return true
|
||||
}
|
||||
var stack = [TreeNode?]()
|
||||
stack.append(root.left)
|
||||
stack.append(root.right)
|
||||
while !stack.isEmpty {
|
||||
let left = stack.removeLast()
|
||||
let right = stack.removeLast()
|
||||
|
||||
if left == nil && right == nil {
|
||||
continue
|
||||
}
|
||||
if left == nil || right == nil || left?.val != right?.val {
|
||||
return false
|
||||
}
|
||||
stack.append(left!.left)
|
||||
stack.append(right!.right)
|
||||
stack.append(left!.right)
|
||||
stack.append(right!.left)
|
||||
}
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -246,6 +246,34 @@ var levelOrder = function(root) {
|
||||
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func levelOrder(_ root: TreeNode?) -> [[Int]] {
|
||||
var res = [[Int]]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var sub = [Int]()
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
sub.append(node.val)
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
res.append(sub)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
**此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!**
|
||||
|
||||
|
||||
@ -426,6 +454,31 @@ var levelOrderBottom = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
|
||||
var res = [[Int]]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue: [TreeNode] = [root]
|
||||
while !queue.isEmpty {
|
||||
var sub = [Int]()
|
||||
for _ in 0 ..< queue.count {
|
||||
let node = queue.removeFirst()
|
||||
sub.append(node.val)
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
res.insert(sub, at: 0)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
# 199.二叉树的右视图
|
||||
|
||||
@ -604,6 +657,36 @@ var rightSideView = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func rightSideView(_ root: TreeNode?) -> [Int] {
|
||||
var res = [Int]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
for i in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
if i == size - 1 {
|
||||
// 保存 每层最后一个元素
|
||||
res.append(node.val)
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 637.二叉树的层平均值
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/)
|
||||
@ -785,6 +868,34 @@ var averageOfLevels = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func averageOfLevels(_ root: TreeNode?) -> [Double] {
|
||||
var res = [Double]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var sum = 0
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
sum += node.val
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
res.append(Double(sum) / Double(size))
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
# 429.N叉树的层序遍历
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/)
|
||||
@ -981,6 +1092,31 @@ var levelOrder = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func levelOrder(_ root: Node?) -> [[Int]] {
|
||||
var res = [[Int]]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue = [Node]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var sub = [Int]()
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
sub.append(node.val)
|
||||
for childNode in node.children {
|
||||
queue.append(childNode)
|
||||
}
|
||||
}
|
||||
res.append(sub)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
# 515.在每个树行中找最大值
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
|
||||
@ -1136,6 +1272,36 @@ var largestValues = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func largestValues(_ root: TreeNode?) -> [Int] {
|
||||
var res = [Int]()
|
||||
guard let root = root else {
|
||||
return res
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var max: Int = Int.min
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
if node.val > max {
|
||||
max = node.val
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
res.append(max)
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
# 116.填充每个节点的下一个右侧节点指针
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
|
||||
@ -1338,6 +1504,37 @@ func connect(root *Node) *Node {
|
||||
}
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func connect(_ root: Node?) -> Node? {
|
||||
guard let root = root else {
|
||||
return nil
|
||||
}
|
||||
var queue = [Node]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var preNode: Node?
|
||||
for i in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
if i == 0 {
|
||||
preNode = node
|
||||
} else {
|
||||
preNode?.next = node
|
||||
preNode = node
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return root
|
||||
}
|
||||
```
|
||||
|
||||
# 117.填充每个节点的下一个右侧节点指针II
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
|
||||
@ -1532,6 +1729,38 @@ func connect(root *Node) *Node {
|
||||
return root
|
||||
}
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func connect(_ root: Node?) -> Node? {
|
||||
guard let root = root else {
|
||||
return nil
|
||||
}
|
||||
var queue = [Node]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
var preNode: Node?
|
||||
for i in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
if i == 0 {
|
||||
preNode = node
|
||||
} else {
|
||||
preNode?.next = node
|
||||
preNode = node
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return root
|
||||
}
|
||||
```
|
||||
|
||||
# 104.二叉树的最大深度
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
|
||||
@ -1704,6 +1933,31 @@ var maxDepth = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func maxDepth(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
var res: Int = 0
|
||||
while !queue.isEmpty {
|
||||
for _ in 0 ..< queue.count {
|
||||
let node = queue.removeFirst()
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
res += 1
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
# 111.二叉树的最小深度
|
||||
|
||||
[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
|
||||
@ -1876,7 +2130,33 @@ var minDepth = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
Swift:
|
||||
```swift
|
||||
func minDepth(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var res = 0
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
res += 1
|
||||
for _ in 0 ..< queue.count {
|
||||
let node = queue.removeFirst()
|
||||
if node.left == nil && node.right == nil {
|
||||
return res
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 总结
|
||||
|
@ -653,5 +653,82 @@ int maxDepth(struct TreeNode* root){
|
||||
}
|
||||
```
|
||||
|
||||
## Swift
|
||||
|
||||
>二叉树最大深度
|
||||
```swift
|
||||
// 递归 - 后序
|
||||
func maxDepth1(_ root: TreeNode?) -> Int {
|
||||
return _maxDepth1(root)
|
||||
}
|
||||
func _maxDepth1(_ root: TreeNode?) -> Int {
|
||||
if root == nil {
|
||||
return 0
|
||||
}
|
||||
let leftDepth = _maxDepth1(root!.left)
|
||||
let rightDepth = _maxDepth1(root!.right)
|
||||
return 1 + max(leftDepth, rightDepth)
|
||||
}
|
||||
|
||||
// 层序
|
||||
func maxDepth(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
var res: Int = 0
|
||||
while !queue.isEmpty {
|
||||
res += 1
|
||||
for _ in 0 ..< queue.count {
|
||||
let node = queue.removeFirst()
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
>N叉树最大深度
|
||||
```swift
|
||||
// 递归
|
||||
func maxDepth(_ root: Node?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var depth = 0
|
||||
for node in root.children {
|
||||
depth = max(depth, maxDepth(node))
|
||||
}
|
||||
return depth + 1
|
||||
}
|
||||
|
||||
// 迭代-层序遍历
|
||||
func maxDepth1(_ root: Node?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var depth = 0
|
||||
var queue = [Node]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
depth += 1
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
for child in node.children {
|
||||
queue.append(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
return depth
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -816,6 +816,7 @@ var buildTree = function(preorder, inorder) {
|
||||
|
||||
## C
|
||||
106 从中序与后序遍历序列构造二叉树
|
||||
|
||||
```c
|
||||
int linearSearch(int* arr, int arrSize, int key) {
|
||||
int i;
|
||||
@ -847,6 +848,7 @@ struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int po
|
||||
```
|
||||
|
||||
105 从前序与中序遍历序列构造二叉树
|
||||
|
||||
```c
|
||||
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
|
||||
// 递归结束条件:传入的数组大小为0
|
||||
@ -889,5 +891,100 @@ struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int in
|
||||
}
|
||||
```
|
||||
|
||||
## Swift
|
||||
|
||||
105 从前序与中序遍历序列构造二叉树
|
||||
|
||||
```swift
|
||||
class Solution {
|
||||
func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? {
|
||||
return helper(preorder: preorder,
|
||||
preorderBegin: 0,
|
||||
preorderEnd: preorder.count,
|
||||
inorder: inorder,
|
||||
inorderBegin: 0,
|
||||
inorderEnd: inorder.count)
|
||||
}
|
||||
|
||||
func helper(preorder: [Int], preorderBegin: Int, preorderEnd: Int, inorder: [Int], inorderBegin: Int, inorderEnd: Int) -> TreeNode? {
|
||||
if preorderBegin == preorderEnd {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 前序遍历数组的第一个元素作为分割点
|
||||
let rootValue = preorder[preorderBegin]
|
||||
let root = TreeNode(rootValue)
|
||||
|
||||
|
||||
if preorderEnd - preorderBegin == 1 {
|
||||
return root
|
||||
}
|
||||
|
||||
var index = 0 // 从中序遍历数组中找到根节点的下标
|
||||
if let ind = inorder.firstIndex(of: rootValue) {
|
||||
index = ind
|
||||
}
|
||||
|
||||
// 递归
|
||||
root.left = helper(preorder: preorder,
|
||||
preorderBegin: preorderBegin + 1,
|
||||
preorderEnd: preorderBegin + 1 + index - inorderBegin,
|
||||
inorder: inorder,
|
||||
inorderBegin: inorderBegin,
|
||||
inorderEnd: index)
|
||||
root.right = helper(preorder: preorder,
|
||||
preorderBegin: preorderBegin + 1 + index - inorderBegin,
|
||||
preorderEnd: preorderEnd,
|
||||
inorder: inorder,
|
||||
inorderBegin: index + 1,
|
||||
inorderEnd: inorderEnd)
|
||||
return root
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
106 从中序与后序遍历序列构造二叉树
|
||||
|
||||
```swift
|
||||
class Solution_0106 {
|
||||
func buildTree(inorder: [Int], inorderBegin: Int, inorderEnd: Int, postorder: [Int], postorderBegin: Int, postorderEnd: Int) -> TreeNode? {
|
||||
if postorderEnd - postorderBegin < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 后序遍历数组的最后一个元素作为分割点
|
||||
let rootValue = postorder[postorderEnd - 1]
|
||||
let root = TreeNode(rootValue)
|
||||
|
||||
if postorderEnd - postorderBegin == 1 {
|
||||
return root
|
||||
}
|
||||
|
||||
// 从中序遍历数组中找到根节点的下标
|
||||
var delimiterIndex = 0
|
||||
if let index = inorder.firstIndex(of: rootValue) {
|
||||
delimiterIndex = index
|
||||
}
|
||||
|
||||
root.left = buildTree(inorder: inorder,
|
||||
inorderBegin: inorderBegin,
|
||||
inorderEnd: delimiterIndex,
|
||||
postorder: postorder,
|
||||
postorderBegin: postorderBegin,
|
||||
postorderEnd: postorderBegin + (delimiterIndex - inorderBegin))
|
||||
|
||||
root.right = buildTree(inorder: inorder,
|
||||
inorderBegin: delimiterIndex + 1,
|
||||
inorderEnd: inorderEnd,
|
||||
postorder: postorder,
|
||||
postorderBegin: postorderBegin + (delimiterIndex - inorderBegin),
|
||||
postorderEnd: postorderEnd - 1)
|
||||
return root
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -404,8 +404,51 @@ var minDepth = function(root) {
|
||||
};
|
||||
```
|
||||
|
||||
## Swift
|
||||
|
||||
> 递归
|
||||
```Swift
|
||||
func minDepth(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
if root.left == nil && root.right != nil {
|
||||
return 1 + minDepth(root.right)
|
||||
}
|
||||
if root.left != nil && root.right == nil {
|
||||
return 1 + minDepth(root.left)
|
||||
}
|
||||
return 1 + min(minDepth(root.left), minDepth(root.right))
|
||||
}
|
||||
```
|
||||
|
||||
> 迭代
|
||||
```Swift
|
||||
func minDepth(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var res = 0
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
res += 1
|
||||
for _ in 0 ..< queue.count {
|
||||
let node = queue.removeFirst()
|
||||
if node.left == nil && node.right == nil {
|
||||
return res
|
||||
}
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -587,5 +587,57 @@ func partition(_ s: String) -> [[String]] {
|
||||
}
|
||||
```
|
||||
|
||||
## Rust
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn partition(s: String) -> Vec<Vec<String>> {
|
||||
let mut ret = vec![];
|
||||
let mut path = vec![];
|
||||
let sub_str: Vec<char> = s.chars().collect();
|
||||
|
||||
Self::backtracing(&sub_str, 0, &mut ret, &mut path);
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn backtracing(sub_str: &Vec<char>, start: usize, ret: &mut Vec<Vec<String>>, path: &mut Vec<String>) {
|
||||
//如果起始位置大于s的大小,说明找到了一组分割方案
|
||||
if start >= sub_str.len() {
|
||||
ret.push(path.clone());
|
||||
return;
|
||||
}
|
||||
|
||||
for i in start..sub_str.len() {
|
||||
if !Self::is_palindrome(sub_str, start, i) {
|
||||
continue;
|
||||
}
|
||||
//如果是回文子串,则记录
|
||||
let s: String = sub_str[start..i+1].into_iter().collect();
|
||||
path.push(s);
|
||||
|
||||
//起始位置后移,保证不重复
|
||||
Self::backtracing(sub_str, i+1, ret, path);
|
||||
path.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn is_palindrome(s: &Vec<char>, start: usize, end: usize) -> bool {
|
||||
let (mut start, mut end) = (start, end);
|
||||
|
||||
while start < end {
|
||||
if s[start] != s[end] {
|
||||
return false;
|
||||
}
|
||||
|
||||
start += 1;
|
||||
end -= 1;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
```
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -133,39 +133,26 @@ public:
|
||||
java:
|
||||
|
||||
```Java
|
||||
public class EvalRPN {
|
||||
|
||||
class Solution {
|
||||
public int evalRPN(String[] tokens) {
|
||||
Deque<Integer> stack = new LinkedList();
|
||||
for (String token : tokens) {
|
||||
char c = token.charAt(0);
|
||||
if (!isOpe(token)) {
|
||||
stack.addFirst(stoi(token));
|
||||
} else if (c == '+') {
|
||||
stack.push(stack.pop() + stack.pop());
|
||||
} else if (c == '-') {
|
||||
for (int i = 0; i < tokens.length; ++i) {
|
||||
if ("+".equals(tokens[i])) { // leetcode 内置jdk的问题,不能使用==判断字符串是否相等
|
||||
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
|
||||
} else if ("-".equals(tokens[i])) {
|
||||
stack.push(-stack.pop() + stack.pop());
|
||||
} else if (c == '*') {
|
||||
} else if ("*".equals(tokens[i])) {
|
||||
stack.push(stack.pop() * stack.pop());
|
||||
} else if ("/".equals(tokens[i])) {
|
||||
int temp1 = stack.pop();
|
||||
int temp2 = stack.pop();
|
||||
stack.push(temp2 / temp1);
|
||||
} else {
|
||||
int num1 = stack.pop();
|
||||
int num2 = stack.pop();
|
||||
stack.push( num2/num1);
|
||||
stack.push(Integer.valueOf(tokens[i]));
|
||||
}
|
||||
}
|
||||
return stack.pop();
|
||||
}
|
||||
private boolean isOpe(String s) {
|
||||
return s.length() == 1 && s.charAt(0) <'0' || s.charAt(0) >'9';
|
||||
}
|
||||
private int stoi(String s) {
|
||||
return Integer.valueOf(s);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new EvalRPN().evalRPN(new String[] {"10","6","9","3","+","-11","*","/","*","17","+","5","+"});
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
|
||||
|
||||
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒叙了,那么再把单词反转一下,单词不就正过来了。
|
||||
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。
|
||||
|
||||
所以解题思路如下:
|
||||
|
||||
|
@ -302,7 +302,63 @@ var removeElements = function(head, val) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
版本一(在原链表上直接删除):
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* class ListNode {
|
||||
* val: number
|
||||
* next: ListNode | null
|
||||
* constructor(val?: number, next?: ListNode | null) {
|
||||
* this.val = (val===undefined ? 0 : val)
|
||||
* this.next = (next===undefined ? null : next)
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
function removeElements(head: ListNode | null, val: number): ListNode | null {
|
||||
// 删除头部节点
|
||||
while (head !== null && head.val === val) {
|
||||
head = head.next;
|
||||
}
|
||||
if (head === null) return head;
|
||||
let pre: ListNode = head, cur: ListNode = head.next;
|
||||
// 删除非头部节点
|
||||
while (cur) {
|
||||
if (cur.val === val) {
|
||||
pre.next = cur.next;
|
||||
} else {
|
||||
pre = pre.next;
|
||||
}
|
||||
cur = cur.next;
|
||||
}
|
||||
return head;
|
||||
};
|
||||
```
|
||||
|
||||
版本二(虚拟头节点):
|
||||
|
||||
```typescript
|
||||
function removeElements(head: ListNode | null, val: number): ListNode | null {
|
||||
head = new ListNode(0, head);
|
||||
let pre: ListNode = head, cur: ListNode = head.next;
|
||||
// 删除非头部节点
|
||||
while (cur) {
|
||||
if (cur.val === val) {
|
||||
pre.next = cur.next;
|
||||
} else {
|
||||
pre = pre.next;
|
||||
}
|
||||
cur = cur.next;
|
||||
}
|
||||
return head.next;
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
|
||||
```swift
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
|
@ -314,6 +314,54 @@ var reverseList = function(head) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
// 双指针法
|
||||
function reverseList(head: ListNode | null): ListNode | null {
|
||||
let preNode: ListNode | null = null,
|
||||
curNode: ListNode | null = head,
|
||||
tempNode: ListNode | null;
|
||||
while (curNode) {
|
||||
tempNode = curNode.next;
|
||||
curNode.next = preNode;
|
||||
preNode = curNode;
|
||||
curNode = tempNode;
|
||||
}
|
||||
return preNode;
|
||||
};
|
||||
|
||||
// 递归(从前往后翻转)
|
||||
function reverseList(head: ListNode | null): ListNode | null {
|
||||
function recur(preNode: ListNode | null, curNode: ListNode | null): ListNode | null {
|
||||
if (curNode === null) return preNode;
|
||||
let tempNode: ListNode | null = curNode.next;
|
||||
curNode.next = preNode;
|
||||
preNode = curNode;
|
||||
curNode = tempNode;
|
||||
return recur(preNode, curNode);
|
||||
}
|
||||
return recur(null, head);
|
||||
};
|
||||
|
||||
// 递归(从后往前翻转)
|
||||
function reverseList(head: ListNode | null): ListNode | null {
|
||||
if (head === null) return null;
|
||||
let newHead: ListNode | null;
|
||||
function recur(node: ListNode | null, preNode: ListNode | null): void {
|
||||
if (node.next === null) {
|
||||
newHead = node;
|
||||
newHead.next = preNode;
|
||||
} else {
|
||||
recur(node.next, node);
|
||||
node.next = preNode;
|
||||
}
|
||||
}
|
||||
recur(head, null);
|
||||
return newHead;
|
||||
};
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
|
@ -121,7 +121,6 @@ public:
|
||||
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@ -214,6 +213,28 @@ var minSubArrayLen = function(target, nums) {
|
||||
};
|
||||
```
|
||||
|
||||
Typescript:
|
||||
|
||||
```typescript
|
||||
function minSubArrayLen(target: number, nums: number[]): number {
|
||||
let left: number = 0, right: number = 0;
|
||||
let res: number = nums.length + 1;
|
||||
let sum: number = 0;
|
||||
while (right < nums.length) {
|
||||
sum += nums[right];
|
||||
if (sum >= target) {
|
||||
// 不断移动左指针,直到不能再缩小为止
|
||||
while (sum - nums[left] >= target) {
|
||||
sum -= nums[left++];
|
||||
}
|
||||
res = Math.min(res, right - left + 1);
|
||||
}
|
||||
right++;
|
||||
}
|
||||
return res === nums.length + 1 ? 0 : res;
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
|
||||
```swift
|
||||
@ -291,5 +312,23 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
def min_sub_array_len(target, nums)
|
||||
res = Float::INFINITY # 无穷大
|
||||
i, sum = 0, 0
|
||||
nums.length.times do |j|
|
||||
sum += nums[j]
|
||||
while sum >= target
|
||||
res = [res, j - i + 1].min
|
||||
sum -= nums[i]
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
res == Float::INFINITY ? 0 : res
|
||||
end
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -323,7 +323,6 @@ class Solution:
|
||||
self.backtracking(k, n, i + 1)
|
||||
self.path.pop()
|
||||
self.sum_now -= i
|
||||
return
|
||||
```
|
||||
|
||||
## Go
|
||||
|
@ -80,7 +80,7 @@ return treeNum;
|
||||
class Solution {
|
||||
private:
|
||||
int getNodesNum(TreeNode* cur) {
|
||||
if (cur == 0) return 0;
|
||||
if (cur == NULL) return 0;
|
||||
int leftNum = getNodesNum(cur->left); // 左
|
||||
int rightNum = getNodesNum(cur->right); // 右
|
||||
int treeNum = leftNum + rightNum + 1; // 中
|
||||
@ -522,5 +522,73 @@ int countNodes(struct TreeNode* root){
|
||||
}
|
||||
```
|
||||
|
||||
## Swift:
|
||||
|
||||
> 递归
|
||||
```swift
|
||||
func countNodes(_ root: TreeNode?) -> Int {
|
||||
return _countNodes(root)
|
||||
}
|
||||
func _countNodes(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
let leftCount = _countNodes(root.left)
|
||||
let rightCount = _countNodes(root.right)
|
||||
return 1 + leftCount + rightCount
|
||||
}
|
||||
```
|
||||
|
||||
> 层序遍历
|
||||
```Swift
|
||||
func countNodes(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var res = 0
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let size = queue.count
|
||||
for _ in 0 ..< size {
|
||||
let node = queue.removeFirst()
|
||||
res += 1
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
> 利用完全二叉树性质
|
||||
```Swift
|
||||
func countNodes(_ root: TreeNode?) -> Int {
|
||||
guard let root = root else {
|
||||
return 0
|
||||
}
|
||||
var leftNode = root.left
|
||||
var rightNode = root.right
|
||||
var leftDepth = 0
|
||||
var rightDepth = 0
|
||||
while leftNode != nil {
|
||||
leftNode = leftNode!.left
|
||||
leftDepth += 1
|
||||
}
|
||||
while rightNode != nil {
|
||||
rightNode = rightNode!.right
|
||||
rightDepth += 1
|
||||
}
|
||||
if leftDepth == rightDepth {
|
||||
return (2 << leftDepth) - 1
|
||||
}
|
||||
return countNodes(root.left) + countNodes(root.right) + 1
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -609,5 +609,43 @@ struct TreeNode* invertTree(struct TreeNode* root){
|
||||
}
|
||||
```
|
||||
|
||||
### Swift:
|
||||
```swift
|
||||
// 前序遍历-递归
|
||||
func invertTree(_ root: TreeNode?) -> TreeNode? {
|
||||
guard let root = root else {
|
||||
return root
|
||||
}
|
||||
let tmp = root.left
|
||||
root.left = root.right
|
||||
root.right = tmp
|
||||
let _ = invertTree(root.left)
|
||||
let _ = invertTree(root.right)
|
||||
return root
|
||||
}
|
||||
|
||||
// 层序遍历-迭代
|
||||
func invertTree1(_ root: TreeNode?) -> TreeNode? {
|
||||
guard let root = root else {
|
||||
return nil
|
||||
}
|
||||
var queue = [TreeNode]()
|
||||
queue.append(root)
|
||||
while !queue.isEmpty {
|
||||
let node = queue.removeFirst()
|
||||
let tmp = node.left
|
||||
node.left = node.right
|
||||
node.right = tmp
|
||||
if let left = node.left {
|
||||
queue.append(left)
|
||||
}
|
||||
if let right = node.right {
|
||||
queue.append(right)
|
||||
}
|
||||
}
|
||||
return root
|
||||
}
|
||||
```
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -93,7 +93,7 @@ dp[i][3] = dp[i - 1][2];
|
||||
综上分析,递推代码如下:
|
||||
|
||||
```CPP
|
||||
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i];
|
||||
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);
|
||||
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
|
||||
dp[i][2] = dp[i - 1][0] + prices[i];
|
||||
dp[i][3] = dp[i - 1][2];
|
||||
|
@ -101,7 +101,6 @@ s[j] = tmp;
|
||||
s[i] ^= s[j];
|
||||
s[j] ^= s[i];
|
||||
s[i] ^= s[j];
|
||||
|
||||
```
|
||||
|
||||
这道题目还是比较简单的,但是我正好可以通过这道题目说一说在刷题的时候,使用库函数的原则。
|
||||
|
@ -107,7 +107,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
|
||||
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
|
||||
vector<int> result(k);
|
||||
for (int i = k - 1; i >= 0; i--) {
|
||||
result[i] = pri_que.top().first;
|
||||
@ -142,7 +142,7 @@ class Solution {
|
||||
|
||||
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
|
||||
// 根据map的value值正序排,相当于一个小顶堆
|
||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
|
||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o2.getValue() - o1.getValue());
|
||||
for (Map.Entry<Integer, Integer> entry : entries) {
|
||||
queue.offer(entry);
|
||||
if (queue.size() > k) {
|
||||
@ -180,7 +180,7 @@ class Solution:
|
||||
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
|
||||
heapq.heappop(pri_que)
|
||||
|
||||
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
|
||||
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
|
||||
result = [0] * k
|
||||
for i in range(k-1, -1, -1):
|
||||
result[i] = heapq.heappop(pri_que)[1]
|
||||
|
@ -112,7 +112,7 @@ vector<int> dp(10001, 0);
|
||||
|
||||
4. 确定遍历顺序
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -229,28 +229,24 @@ class Solution {
|
||||
Swift:
|
||||
```swift
|
||||
func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int {
|
||||
// key:a+b的数值,value:a+b数值出现的次数
|
||||
var map = [Int: Int]()
|
||||
// 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中
|
||||
for i in 0 ..< nums1.count {
|
||||
for j in 0 ..< nums2.count {
|
||||
let sum1 = nums1[i] + nums2[j]
|
||||
map[sum1] = (map[sum1] ?? 0) + 1
|
||||
// ab和: ab和出现次数
|
||||
var countDic = [Int: Int]()
|
||||
for a in nums1 {
|
||||
for b in nums2 {
|
||||
let key = a + b
|
||||
countDic[key] = countDic[key, default: 0] + 1
|
||||
}
|
||||
}
|
||||
// 统计a+b+c+d = 0 出现的次数
|
||||
var res = 0
|
||||
// 在遍历大num3和num4数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
|
||||
for i in 0 ..< nums3.count {
|
||||
for j in 0 ..< nums4.count {
|
||||
let sum2 = nums3[i] + nums4[j]
|
||||
let other = 0 - sum2
|
||||
if map.keys.contains(other) {
|
||||
res += map[other]!
|
||||
|
||||
// 通过-(c + d)作为key,去累加ab和出现的次数
|
||||
var result = 0
|
||||
for c in nums3 {
|
||||
for d in nums4 {
|
||||
let key = -(c + d)
|
||||
result += countDic[key, default: 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
这里就要说一说next数组了,next 数组记录的就是最长相同前后缀( [字符串:KMP算法精讲](https://programmercarl.com/0028.实现strStr.html) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀), 如果 next[len - 1] != -1,则说明字符串有最长相同的前后缀(就是字符串里的前缀子串和后缀子串相同的最长长度)。
|
||||
|
||||
最长相等前后缀的长度为:next[len - 1] + 1。
|
||||
最长相等前后缀的长度为:next[len - 1] + 1。(这里的next数组是以统一减一的方式计算的,因此需要+1)
|
||||
|
||||
数组长度为:len。
|
||||
|
||||
|
@ -154,6 +154,8 @@ public:
|
||||
|
||||
|
||||
Java:
|
||||
|
||||
> 动态规划:
|
||||
```java
|
||||
/**
|
||||
* 1.dp[i] 代表当前下标最大连续值
|
||||
@ -180,6 +182,25 @@ Java:
|
||||
}
|
||||
```
|
||||
|
||||
> 贪心法:
|
||||
|
||||
```Java
|
||||
public static int findLengthOfLCIS(int[] nums) {
|
||||
if (nums.length == 0) return 0;
|
||||
int res = 1; // 连续子序列最少也是1
|
||||
int count = 1;
|
||||
for (int i = 0; i < nums.length - 1; i++) {
|
||||
if (nums[i + 1] > nums[i]) { // 连续记录
|
||||
count++;
|
||||
} else { // 不连续,count从头开始
|
||||
count = 1;
|
||||
}
|
||||
if (count > res) res = count;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
> 动态规划:
|
||||
|
@ -68,7 +68,7 @@ for (int i = 0; i < n; i++) {
|
||||
|
||||
```cpp
|
||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
||||
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
for (int i = n - 1; i >= 0; i--) {
|
||||
if (inDegree[edges[i][1]] == 2) {
|
||||
vec.push_back(i);
|
||||
@ -577,7 +577,7 @@ var findRedundantDirectedConnection = function(edges) {
|
||||
inDegree[edges[i][1]]++; // 统计入度
|
||||
}
|
||||
let vec = [];// 记录入度为2的边(如果有的话就两条边)
|
||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
||||
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||
for (let i = n - 1; i >= 0; i--) {
|
||||
if (inDegree[edges[i][1]] == 2) {
|
||||
vec.push(i);
|
||||
|
@ -284,7 +284,6 @@ func search(nums []int, target int) int {
|
||||
* @param {number} target
|
||||
* @return {number}
|
||||
*/
|
||||
/**
|
||||
var search = function(nums, target) {
|
||||
let left = 0, right = nums.length - 1;
|
||||
// 使用左闭右闭区间
|
||||
@ -326,6 +325,46 @@ var search = function(nums, target) {
|
||||
};
|
||||
```
|
||||
|
||||
**TypeScript**
|
||||
|
||||
(版本一)左闭右闭区间
|
||||
|
||||
```typescript
|
||||
function search(nums: number[], target: number): number {
|
||||
let left: number = 0, right: number = nums.length - 1;
|
||||
while (left <= right) {
|
||||
let mid: number = left + Math.floor((right - left) / 2);
|
||||
if (nums[mid] > target) {
|
||||
right = mid - 1;
|
||||
} else if (nums[mid] < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
|
||||
(版本二)左闭右开区间
|
||||
|
||||
```typescript
|
||||
function search(nums: number[], target: number): number {
|
||||
let left: number = 0, right: number = nums.length;
|
||||
while (left < right) {
|
||||
let mid: number = left + Math.floor((right - left) / 2);
|
||||
if (nums[mid] > target) {
|
||||
right = mid;
|
||||
} else if (nums[mid] < target) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
return mid;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
```
|
||||
|
||||
**Ruby:**
|
||||
|
||||
```ruby
|
||||
|
@ -119,7 +119,7 @@ C++代码如下:
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> dailyTemperatures(vector<int>& T) {
|
||||
// 递减栈
|
||||
// 递增栈
|
||||
stack<int> st;
|
||||
vector<int> result(T.size(), 0);
|
||||
st.push(0);
|
||||
@ -150,7 +150,7 @@ public:
|
||||
class Solution {
|
||||
public:
|
||||
vector<int> dailyTemperatures(vector<int>& T) {
|
||||
stack<int> st; // 递减栈
|
||||
stack<int> st; // 递增栈
|
||||
vector<int> result(T.size(), 0);
|
||||
for (int i = 0; i < T.size(); i++) {
|
||||
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
|
||||
@ -178,7 +178,7 @@ public:
|
||||
Java:
|
||||
```java
|
||||
/**
|
||||
* 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到笑
|
||||
* 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到小
|
||||
* <p>
|
||||
* 入站元素要和当前栈内栈首元素进行比较
|
||||
* 若大于栈首则 则与元素下标做差
|
||||
|
@ -82,7 +82,7 @@ dp[1] = cost[1];
|
||||
|
||||
**但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来**。
|
||||
|
||||
例如:01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒叙呢?
|
||||
例如:01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒序呢?
|
||||
|
||||
**这些都是遍历顺序息息相关。当然背包问题后续「代码随想录」都会重点讲解的!**
|
||||
|
||||
|
@ -221,6 +221,35 @@ var sortedSquares = function(nums) {
|
||||
};
|
||||
```
|
||||
|
||||
Typescript:
|
||||
|
||||
双指针法:
|
||||
|
||||
```typescript
|
||||
function sortedSquares(nums: number[]): number[] {
|
||||
let left: number = 0, right: number = nums.length - 1;
|
||||
let resArr: number[] = new Array(nums.length);
|
||||
let resArrIndex: number = resArr.length - 1;
|
||||
while (left <= right) {
|
||||
if (Math.abs(nums[left]) < Math.abs(nums[right])) {
|
||||
resArr[resArrIndex] = nums[right--] ** 2;
|
||||
} else {
|
||||
resArr[resArrIndex] = nums[left++] ** 2;
|
||||
}
|
||||
resArrIndex--;
|
||||
}
|
||||
return resArr;
|
||||
};
|
||||
```
|
||||
|
||||
骚操作法(暴力思路):
|
||||
|
||||
```typescript
|
||||
function sortedSquares(nums: number[]): number[] {
|
||||
return nums.map(i => i * i).sort((a, b) => a - b);
|
||||
};
|
||||
```
|
||||
|
||||
Swift:
|
||||
|
||||
```swift
|
||||
|
@ -58,7 +58,7 @@ words[i] 由小写英文字母组成
|
||||
|
||||
先统计第一个字符串所有字符出现的次数,代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
|
||||
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
||||
hash[A[0][i] - 'a']++;
|
||||
@ -71,7 +71,7 @@ for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
|
||||
for (int i = 1; i < A.size(); i++) {
|
||||
memset(hashOtherStr, 0, 26 * sizeof(int));
|
||||
@ -84,11 +84,11 @@ for (int i = 1; i < A.size(); i++) {
|
||||
}
|
||||
}
|
||||
```
|
||||
此时hash里统计着字符在所有字符串里出现的最小次数,那么把hash转正题目要求的输出格式就可以了。
|
||||
此时hash里统计着字符在所有字符串里出现的最小次数,那么把hash转成题目要求的输出格式就可以了。
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
// 将hash统计的字符次数,转成输出形式
|
||||
for (int i = 0; i < 26; i++) {
|
||||
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
||||
|
@ -63,7 +63,7 @@
|
||||
|
||||

|
||||
|
||||
从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒叙的,所以在对字符串进行反转一下,就得到了最终的结果。
|
||||
从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒序的,所以在对字符串进行反转一下,就得到了最终的结果。
|
||||
|
||||
C++代码 :
|
||||
|
||||
|
@ -87,7 +87,7 @@ vector<int> dp(15001, 0);
|
||||
4. 确定遍历顺序
|
||||
|
||||
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -103,7 +103,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
|
||||
|
||||
为什么呢?
|
||||
|
||||
**倒叙遍历是为了保证物品i只被放入一次!**。但如果一旦正序遍历了,那么物品0就会被重复加入多次!
|
||||
**倒序遍历是为了保证物品i只被放入一次!**。但如果一旦正序遍历了,那么物品0就会被重复加入多次!
|
||||
|
||||
举一个例子:物品0的重量weight[0] = 1,价值value[0] = 15
|
||||
|
||||
@ -115,9 +115,9 @@ dp[2] = dp[2 - weight[0]] + value[0] = 30
|
||||
|
||||
此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。
|
||||
|
||||
为什么倒叙遍历,就可以保证物品只放入一次呢?
|
||||
为什么倒序遍历,就可以保证物品只放入一次呢?
|
||||
|
||||
倒叙就是先算dp[2]
|
||||
倒序就是先算dp[2]
|
||||
|
||||
dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)
|
||||
|
||||
@ -125,7 +125,7 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15
|
||||
|
||||
所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。
|
||||
|
||||
**那么问题又来了,为什么二维dp数组历的时候不用倒叙呢?**
|
||||
**那么问题又来了,为什么二维dp数组历的时候不用倒序呢?**
|
||||
|
||||
因为对于二维dp,dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖!
|
||||
|
||||
|
@ -168,6 +168,32 @@ public class ListNode {
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
class ListNode {
|
||||
val;
|
||||
next = null;
|
||||
constructor(value) {
|
||||
this.val = value;
|
||||
this.next = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
class ListNode {
|
||||
public val: number;
|
||||
public next: ListNode = null;
|
||||
constructor(value: number) {
|
||||
this.val = value;
|
||||
this.next = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user