mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 15:45:40 +08:00
Update
This commit is contained in:
@ -201,6 +201,54 @@ class Solution(object):
|
||||
```
|
||||
|
||||
Go:
|
||||
```go
|
||||
func fourSum(nums []int, target int) [][]int {
|
||||
if len(nums) < 4 {
|
||||
return nil
|
||||
}
|
||||
sort.Ints(nums)
|
||||
var res [][]int
|
||||
for i := 0; i < len(nums)-3; i++ {
|
||||
n1 := nums[i]
|
||||
// if n1 > target { // 不能这样写,因为可能是负数
|
||||
// break
|
||||
// }
|
||||
if i > 0 && n1 == nums[i-1] {
|
||||
continue
|
||||
}
|
||||
for j := i + 1; j < len(nums)-2; j++ {
|
||||
n2 := nums[j]
|
||||
if j > i+1 && n2 == nums[j-1] {
|
||||
continue
|
||||
}
|
||||
l := j + 1
|
||||
r := len(nums) - 1
|
||||
for l < r {
|
||||
n3 := nums[l]
|
||||
n4 := nums[r]
|
||||
sum := n1 + n2 + n3 + n4
|
||||
if sum < target {
|
||||
l++
|
||||
} else if sum > target {
|
||||
r--
|
||||
} else {
|
||||
res = append(res, []int{n1, n2, n3, n4})
|
||||
for l < r && n3 == nums[l+1] { // 去重
|
||||
l++
|
||||
}
|
||||
for l < r && n4 == nums[r-1] { // 去重
|
||||
r--
|
||||
}
|
||||
// 找到答案时,双指针同时靠近
|
||||
r--
|
||||
l++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
javaScript:
|
||||
|
||||
|
@ -86,6 +86,34 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
C:
|
||||
```
|
||||
/**
|
||||
* Definition for singly-linked list.
|
||||
* struct ListNode {
|
||||
* int val;
|
||||
* struct ListNode *next;
|
||||
* };
|
||||
*/
|
||||
|
||||
|
||||
struct ListNode* swapPairs(struct ListNode* head){
|
||||
//使用双指针避免使用中间变量
|
||||
typedef struct ListNode ListNode;
|
||||
ListNode *fakehead = (ListNode *)malloc(sizeof(ListNode));
|
||||
fakehead->next = head;
|
||||
ListNode* right = fakehead->next;
|
||||
ListNode* left = fakehead;
|
||||
while(left && right && right->next ){
|
||||
left->next = right->next;
|
||||
right->next = left->next->next;
|
||||
left->next->next = right;
|
||||
left = right;
|
||||
right = left->next;
|
||||
}
|
||||
return fakehead->next;
|
||||
}
|
||||
```
|
||||
|
||||
Java:
|
||||
|
||||
|
@ -99,6 +99,24 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public void nextPermutation(int[] nums) {
|
||||
for (int i = nums.length - 1; i >= 0; i--) {
|
||||
for (int j = nums.length - 1; j > i; j--) {
|
||||
if (nums[j] > nums[i]) {
|
||||
// 交换
|
||||
int temp = nums[i];
|
||||
nums[i] = nums[j];
|
||||
nums[j] = temp;
|
||||
// [i + 1, nums.length) 内元素升序排序
|
||||
Arrays.sort(nums, i + 1, nums.length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Arrays.sort(nums); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
|
@ -50,7 +50,7 @@
|
||||
|
||||
接下来,在去寻找左边界,和右边界了。
|
||||
|
||||
采用二分法来取寻找左右边界,为了让代码清晰,我分别写两个二分来寻找左边界和右边界。
|
||||
采用二分法来去寻找左右边界,为了让代码清晰,我分别写两个二分来寻找左边界和右边界。
|
||||
|
||||
**刚刚接触二分搜索的同学不建议上来就像如果用一个二分来查找左右边界,很容易把自己绕进去,建议扎扎实实的写两个二分分别找左边界和右边界**
|
||||
|
||||
@ -223,7 +223,7 @@ class Solution {
|
||||
// 解法2
|
||||
// 1、首先,在 nums 数组中二分查找 target;
|
||||
// 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
|
||||
// 3、如果二分查找失败,则 binarySearch 返回 nums 中 为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
|
||||
// 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
|
||||
|
||||
class Solution {
|
||||
public int[] searchRange(int[] nums, int target) {
|
||||
@ -275,6 +275,117 @@ class Solution {
|
||||
## Python
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def searchRange(self, nums: List[int], target: int) -> List[int]:
|
||||
def getRightBorder(nums:List[int], target:int) -> int:
|
||||
left, right = 0, len(nums)-1
|
||||
rightBoder = -2 # 记录一下rightBorder没有被赋值的情况
|
||||
while left <= right:
|
||||
middle = left + (right-left) // 2
|
||||
if nums[middle] > target:
|
||||
right = middle - 1
|
||||
else: # 寻找右边界,nums[middle] == target的时候更新left
|
||||
left = middle + 1
|
||||
rightBoder = left
|
||||
|
||||
return rightBoder
|
||||
|
||||
def getLeftBorder(nums:List[int], target:int) -> int:
|
||||
left, right = 0, len(nums)-1
|
||||
leftBoder = -2 # 记录一下leftBorder没有被赋值的情况
|
||||
while left <= right:
|
||||
middle = left + (right-left) // 2
|
||||
if nums[middle] >= target: # 寻找左边界,nums[middle] == target的时候更新right
|
||||
right = middle - 1;
|
||||
leftBoder = right;
|
||||
else:
|
||||
left = middle + 1
|
||||
return leftBoder
|
||||
leftBoder = getLeftBorder(nums, target)
|
||||
rightBoder = getRightBorder(nums, target)
|
||||
# 情况一
|
||||
if leftBoder == -2 or rightBoder == -2: return [-1, -1]
|
||||
# 情况三
|
||||
if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]
|
||||
# 情况二
|
||||
return [-1, -1]
|
||||
```
|
||||
```python
|
||||
# 解法2
|
||||
# 1、首先,在 nums 数组中二分查找 target;
|
||||
# 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};
|
||||
# 3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
|
||||
class Solution:
|
||||
def searchRange(self, nums: List[int], target: int) -> List[int]:
|
||||
def binarySearch(nums:List[int], target:int) -> int:
|
||||
left, right = 0, len(nums)-1
|
||||
while left<=right: # 不变量:左闭右闭区间
|
||||
middle = left + (right-left) // 2
|
||||
if nums[middle] > target:
|
||||
right = middle - 1
|
||||
elif nums[middle] < target:
|
||||
left = middle + 1
|
||||
else:
|
||||
return middle
|
||||
return -1
|
||||
index = binarySearch(nums, target)
|
||||
if index == -1:return [-1, -1] # nums 中不存在 target,直接返回 {-1, -1}
|
||||
# nums 中存在 targe,则左右滑动指针,来找到符合题意的区间
|
||||
left, right = index, index
|
||||
# 向左滑动,找左边界
|
||||
while left -1 >=0 and nums[left - 1] == target: left -=1
|
||||
# 向右滑动,找右边界
|
||||
while right+1 < len(nums) and nums[right + 1] == target: right +=1
|
||||
return [left, right]
|
||||
```
|
||||
```python
|
||||
# 解法3
|
||||
# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标(左边界)与第一个大于target的下标(右边界);
|
||||
# 2、如果左边界<= 右边界,则返回 [左边界, 右边界]。否则返回[-1, -1]
|
||||
class Solution:
|
||||
def searchRange(self, nums: List[int], target: int) -> List[int]:
|
||||
def binarySearch(nums:List[int], target:int, lower:bool) -> int:
|
||||
left, right = 0, len(nums)-1
|
||||
ans = len(nums)
|
||||
while left<=right: # 不变量:左闭右闭区间
|
||||
middle = left + (right-left) //2
|
||||
# lower为True,执行前半部分,找到第一个大于等于 target的下标 ,否则找到第一个大于target的下标
|
||||
if nums[middle] > target or (lower and nums[middle] >= target):
|
||||
right = middle - 1
|
||||
ans = middle
|
||||
else:
|
||||
left = middle + 1
|
||||
return ans
|
||||
|
||||
leftBorder = binarySearch(nums, target, True) # 搜索左边界
|
||||
rightBorder = binarySearch(nums, target, False) -1 # 搜索右边界
|
||||
if leftBorder<= rightBorder and rightBorder< len(nums) and nums[leftBorder] == target and nums[rightBorder] == target:
|
||||
return [leftBorder, rightBorder]
|
||||
return [-1, -1]
|
||||
```
|
||||
|
||||
```python
|
||||
# 解法4
|
||||
# 1、首先,在 nums 数组中二分查找得到第一个大于等于 target的下标leftBorder;
|
||||
# 2、在 nums 数组中二分查找得到第一个大于等于 target+1的下标, 减1则得到rightBorder;
|
||||
# 3、如果开始位置在数组的右边或者不存在target,则返回[-1, -1] 。否则返回[leftBorder, rightBorder]
|
||||
class Solution:
|
||||
def searchRange(self, nums: List[int], target: int) -> List[int]:
|
||||
def binarySearch(nums:List[int], target:int) -> int:
|
||||
left, right = 0, len(nums)-1
|
||||
while left<=right: # 不变量:左闭右闭区间
|
||||
middle = left + (right-left) //2
|
||||
if nums[middle] >= target:
|
||||
right = middle - 1
|
||||
else:
|
||||
left = middle + 1
|
||||
return left # 若存在target,则返回第一个等于target的值
|
||||
|
||||
leftBorder = binarySearch(nums, target) # 搜索左边界
|
||||
rightBorder = binarySearch(nums, target+1) -1 # 搜索右边界
|
||||
if leftBorder == len(nums) or nums[leftBorder]!= target: # 情况一和情况二
|
||||
return [-1, -1]
|
||||
return [leftBorder, rightBorder]
|
||||
```
|
||||
|
||||
## Go
|
||||
|
@ -138,7 +138,52 @@ class Solution:
|
||||
```
|
||||
|
||||
Go:
|
||||
```Go
|
||||
// solution
|
||||
// 1, dp
|
||||
// 2, 贪心
|
||||
|
||||
func maxSubArray(nums []int) int {
|
||||
n := len(nums)
|
||||
// 这里的dp[i] 表示,最大的连续子数组和,包含num[i] 元素
|
||||
dp := make([]int,n)
|
||||
// 初始化,由于dp 状态转移方程依赖dp[0]
|
||||
dp[0] = nums[0]
|
||||
// 初始化最大的和
|
||||
mx := nums[0]
|
||||
for i:=1;i<n;i++ {
|
||||
// 这里的状态转移方程就是:求最大和
|
||||
// 会面临2种情况,一个是带前面的和,一个是不带前面的和
|
||||
dp[i] = max(dp[i-1]+nums[i],nums[i])
|
||||
mx = max(mx,dp[i])
|
||||
}
|
||||
return mx
|
||||
}
|
||||
|
||||
func max(a,b int) int{
|
||||
if a>b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
const maxSubArray = nums => {
|
||||
// 数组长度,dp初始化
|
||||
const [len, dp] = [nums.length, [nums[0]]];
|
||||
// 最大值初始化为dp[0]
|
||||
let max = dp[0];
|
||||
for (let i = 1; i < len; i++) {
|
||||
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
|
||||
// 更新最大值
|
||||
max = Math.max(max, dp[i]);
|
||||
}
|
||||
return max;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -337,6 +337,8 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
**递归** - 利用BST中序遍历特性,把树"压缩"成数组
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
@ -344,29 +346,56 @@ Python:
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
# 递归法
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
res = [] //把二叉搜索树按中序遍历写成list
|
||||
def buildalist(root):
|
||||
if not root: return
|
||||
buildalist(root.left) //左
|
||||
res.append(root.val) //中
|
||||
buildalist(root.right) //右
|
||||
return res
|
||||
buildalist(root)
|
||||
return res == sorted(res) and len(set(res)) == len(res) //检查list里的数有没有重复元素,以及是否按从小到大排列
|
||||
# 思路: 利用BST中序遍历的特性.
|
||||
# 中序遍历输出的二叉搜索树节点的数值是有序序列
|
||||
candidate_list = []
|
||||
|
||||
def __traverse(root: TreeNode) -> None:
|
||||
nonlocal candidate_list
|
||||
if not root:
|
||||
return
|
||||
__traverse(root.left)
|
||||
candidate_list.append(root.val)
|
||||
__traverse(root.right)
|
||||
|
||||
def __is_sorted(nums: list) -> bool:
|
||||
for i in range(1, len(nums)):
|
||||
if nums[i] <= nums[i - 1]: # ⚠️ 注意: Leetcode定义二叉搜索树中不能有重复元素
|
||||
return False
|
||||
return True
|
||||
|
||||
__traverse(root)
|
||||
res = __is_sorted(candidate_list)
|
||||
|
||||
return res
|
||||
```
|
||||
|
||||
# 简单递归法
|
||||
**递归** - 标准做法
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
def isBST(root, min_val, max_val):
|
||||
if not root: return True
|
||||
if root.val >= max_val or root.val <= min_val:
|
||||
# 规律: BST的中序遍历节点数值是从小到大.
|
||||
cur_max = -float("INF")
|
||||
def __isValidBST(root: TreeNode) -> bool:
|
||||
nonlocal cur_max
|
||||
|
||||
if not root:
|
||||
return True
|
||||
|
||||
is_left_valid = __isValidBST(root.left)
|
||||
if cur_max < root.val:
|
||||
cur_max = root.val
|
||||
else:
|
||||
return False
|
||||
return isBST(root.left, min_val, root.val) and isBST(root.right, root.val, max_val)
|
||||
return isBST(root, float("-inf"), float("inf"))
|
||||
|
||||
is_right_valid = __isValidBST(root.right)
|
||||
|
||||
return is_left_valid and is_right_valid
|
||||
return __isValidBST(root)
|
||||
```
|
||||
```
|
||||
# 迭代-中序遍历
|
||||
class Solution:
|
||||
def isValidBST(self, root: TreeNode) -> bool:
|
||||
|
@ -139,29 +139,29 @@ public:
|
||||
## 迭代法
|
||||
|
||||
```C++
|
||||
lass Solution {
|
||||
class Solution {
|
||||
public:
|
||||
|
||||
bool isSameTree(TreeNode* p, TreeNode* q) {
|
||||
if (p == NULL && q == NULL) return true;
|
||||
if (p == NULL || q == NULL) return false;
|
||||
queue<TreeNode*> que;
|
||||
que.push(p); //
|
||||
que.push(q); //
|
||||
que.push(p); // 添加根节点p
|
||||
que.push(q); // 添加根节点q
|
||||
while (!que.empty()) { //
|
||||
TreeNode* leftNode = que.front(); que.pop();
|
||||
TreeNode* rightNode = que.front(); que.pop();
|
||||
if (!leftNode && !rightNode) { //
|
||||
if (!leftNode && !rightNode) { // 若p的节点与q的节点都为空
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// 若p的节点与q的节点有一个为空或p的节点的值与q节点不同
|
||||
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
|
||||
return false;
|
||||
}
|
||||
que.push(leftNode->left); //
|
||||
que.push(rightNode->left); //
|
||||
que.push(leftNode->right); //
|
||||
que.push(rightNode->right); //
|
||||
que.push(leftNode->left); // 添加p节点的左子树节点
|
||||
que.push(rightNode->left); // 添加q节点的左子树节点点
|
||||
que.push(leftNode->right); // 添加p节点的右子树节点
|
||||
que.push(rightNode->right); // 添加q节点的右子树节点
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -172,8 +172,72 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
Python:
|
||||
```java
|
||||
// 递归法
|
||||
class Solution {
|
||||
public boolean isSameTree(TreeNode p, TreeNode q) {
|
||||
if (p == null && q == null) return true;
|
||||
else if (q == null || p == null) return false;
|
||||
else if (q.val != p.val) return false;
|
||||
return isSameTree(q.left, p.left) && isSameTree(q.right, p.right);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
// 迭代法
|
||||
class Solution {
|
||||
public boolean isSameTree(TreeNode p, TreeNode q) {
|
||||
if(p == null && q == null) return true;
|
||||
if(p == null || q == null) return false;
|
||||
Queue<TreeNode> que= new LinkedList<TreeNode>();
|
||||
que.offer(p);
|
||||
que.offer(q);
|
||||
while(!que.isEmpty()){
|
||||
TreeNode leftNode = que.poll();
|
||||
TreeNode rightNode = que.poll();
|
||||
if(leftNode == null && rightNode == null) continue;
|
||||
if(leftNode == null || rightNode== null || leftNode.val != rightNode.val) return false;
|
||||
que.offer(leftNode.left);
|
||||
que.offer(rightNode.left);
|
||||
que.offer(leftNode.right);
|
||||
que.offer(rightNode.right);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
Python:
|
||||
```python
|
||||
# 递归法
|
||||
class Solution:
|
||||
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
|
||||
if not p and not q: return True
|
||||
elif not p or not q: return False
|
||||
elif p.val != q.val: return False
|
||||
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
|
||||
```
|
||||
|
||||
```python
|
||||
# 迭代法
|
||||
class Solution:
|
||||
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
|
||||
if not p and not q: return True
|
||||
if not p or not q: return False
|
||||
que = collections.deque()
|
||||
que.append(p)
|
||||
que.append(q)
|
||||
while que:
|
||||
leftNode = que.popleft()
|
||||
rightNode = que.popleft()
|
||||
if not leftNode and not rightNode: continue
|
||||
if not leftNode or not rightNode or leftNode.val != rightNode.val: return False
|
||||
que.append(leftNode.left)
|
||||
que.append(rightNode.left)
|
||||
que.append(leftNode.right)
|
||||
que.append(rightNode.right)
|
||||
return True
|
||||
```
|
||||
Go:
|
||||
|
||||
JavaScript:
|
||||
|
@ -1260,6 +1260,7 @@ func connect(root *Node) *Node {
|
||||
|
||||
# 117.填充每个节点的下一个右侧节点指针II
|
||||
|
||||
|
||||
题目地址:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/
|
||||
|
||||
思路:
|
||||
@ -1300,6 +1301,43 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
Java 代码:
|
||||
|
||||
```java
|
||||
// 二叉树之层次遍历
|
||||
class Solution {
|
||||
public Node connect(Node root) {
|
||||
Queue<Node> queue = new LinkedList<>();
|
||||
if (root != null) {
|
||||
queue.add(root);
|
||||
}
|
||||
while (!queue.isEmpty()) {
|
||||
int size = queue.size();
|
||||
Node node = null;
|
||||
Node nodePre = null;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i == 0) {
|
||||
nodePre = queue.poll(); // 取出本层头一个节点
|
||||
node = nodePre;
|
||||
} else {
|
||||
node = queue.poll();
|
||||
nodePre.next = node; // 本层前一个节点 next 指向当前节点
|
||||
nodePre = nodePre.next;
|
||||
}
|
||||
if (node.left != null) {
|
||||
queue.add(node.left);
|
||||
}
|
||||
if (node.right != null) {
|
||||
queue.add(node.right);
|
||||
}
|
||||
}
|
||||
nodePre.next = null; // 本层最后一个节点 next 指向 null
|
||||
}
|
||||
return root;
|
||||
}
|
||||
}
|
||||
```
|
||||
python代码:
|
||||
|
||||
```python
|
||||
|
@ -654,43 +654,68 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
105.从前序与中序遍历序列构造二叉树
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
|
||||
if not preorder: return None //特殊情况
|
||||
root = TreeNode(preorder[0]) //新建父节点
|
||||
p=inorder.index(preorder[0]) //找到父节点在中序遍历的位置(因为没有重复的元素,才可以这样找)
|
||||
root.left = self.buildTree(preorder[1:p+1],inorder[:p]) //注意左节点时分割中序数组和前续数组的开闭环
|
||||
root.right = self.buildTree(preorder[p+1:],inorder[p+1:]) //分割中序数组和前续数组
|
||||
return root
|
||||
# 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
|
||||
if not preorder:
|
||||
return None
|
||||
|
||||
# 第二步: 前序遍历的第一个就是当前的中间节点.
|
||||
root_val = preorder[0]
|
||||
root = TreeNode(root_val)
|
||||
|
||||
# 第三步: 找切割点.
|
||||
separator_idx = inorder.index(root_val)
|
||||
|
||||
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
|
||||
inorder_left = inorder[:separator_idx]
|
||||
inorder_right = inorder[separator_idx + 1:]
|
||||
|
||||
# 第五步: 切割preorder数组. 得到preorder数组的左,右半边.
|
||||
# ⭐️ 重点1: 中序数组大小一定跟前序数组大小是相同的.
|
||||
preorder_left = preorder[1:1 + len(inorder_left)]
|
||||
preorder_right = preorder[1 + len(inorder_left):]
|
||||
|
||||
# 第六步: 递归
|
||||
root.left = self.buildTree(preorder_left, inorder_left)
|
||||
root.right = self.buildTree(preorder_right, inorder_right)
|
||||
|
||||
return root
|
||||
```
|
||||
106.从中序与后序遍历序列构造二叉树
|
||||
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
|
||||
if not postorder: return None //特殊情况
|
||||
root = TreeNode(postorder[-1]) //新建父节点
|
||||
p=inorder.index(postorder[-1]) //找到父节点在中序遍历的位置*因为没有重复的元素,才可以这样找
|
||||
root.left = self.buildTree(inorder[:p],postorder[:p]) //分割中序数组和后续数组
|
||||
root.right = self.buildTree(inorder[p+1:],postorder[p:-1]) //注意右节点时分割中序数组和后续数组的开闭环
|
||||
return root
|
||||
# 第一步: 特殊情况讨论: 树为空. (递归终止条件)
|
||||
if not postorder:
|
||||
return None
|
||||
|
||||
# 第二步: 后序遍历的最后一个就是当前的中间节点.
|
||||
root_val = postorder[-1]
|
||||
root = TreeNode(root_val)
|
||||
|
||||
# 第三步: 找切割点.
|
||||
separator_idx = inorder.index(root_val)
|
||||
|
||||
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
|
||||
inorder_left = inorder[:separator_idx]
|
||||
inorder_right = inorder[separator_idx + 1:]
|
||||
|
||||
# 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
|
||||
# ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
|
||||
postorder_left = postorder[:len(inorder_left)]
|
||||
postorder_right = postorder[len(inorder_left): len(postorder) - 1]
|
||||
|
||||
# 第六步: 递归
|
||||
root.left = self.buildTree(inorder_left, postorder_left)
|
||||
root.right = self.buildTree(inorder_right, postorder_right)
|
||||
|
||||
return root
|
||||
```
|
||||
Go:
|
||||
> 106 从中序与后序遍历序列构造二叉树
|
||||
|
@ -416,6 +416,8 @@ class Solution {
|
||||
Python:
|
||||
|
||||
0112.路径总和
|
||||
|
||||
**递归**
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
@ -424,28 +426,56 @@ Python:
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
|
||||
// 递归法
|
||||
|
||||
class Solution:
|
||||
def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
|
||||
def isornot(root,targetSum)->bool:
|
||||
if (not root.left) and (not root.right) and targetSum == 0:return True // 遇到叶子节点,并且计数为0
|
||||
if (not root.left) and (not root.right):return False //遇到叶子节点,计数不为0
|
||||
def isornot(root, targetSum) -> bool:
|
||||
if (not root.left) and (not root.right) and targetSum == 0:
|
||||
return True # 遇到叶子节点,并且计数为0
|
||||
if (not root.left) and (not root.right):
|
||||
return False # 遇到叶子节点,计数不为0
|
||||
if root.left:
|
||||
targetSum -= root.left.val //左节点
|
||||
if isornot(root.left,targetSum):return True //递归,处理左节点
|
||||
targetSum += root.left.val //回溯
|
||||
targetSum -= root.left.val # 左节点
|
||||
if isornot(root.left, targetSum): return True # 递归,处理左节点
|
||||
targetSum += root.left.val # 回溯
|
||||
if root.right:
|
||||
targetSum -= root.right.val //右节点
|
||||
if isornot(root.right,targetSum):return True //递归,处理右节点
|
||||
targetSum += root.right.val //回溯
|
||||
targetSum -= root.right.val # 右节点
|
||||
if isornot(root.right, targetSum): return True # 递归,处理右节点
|
||||
targetSum += root.right.val # 回溯
|
||||
return False
|
||||
|
||||
if root == None:return False //别忘记处理空TreeNode
|
||||
else:return isornot(root,targetSum-root.val)
|
||||
|
||||
if root == None:
|
||||
return False # 别忘记处理空TreeNode
|
||||
else:
|
||||
return isornot(root, targetSum - root.val)
|
||||
```
|
||||
|
||||
**迭代 - 层序遍历**
|
||||
```python
|
||||
class Solution:
|
||||
def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:
|
||||
if not root:
|
||||
return False
|
||||
|
||||
stack = [] # [(当前节点,路径数值), ...]
|
||||
stack.append((root, root.val))
|
||||
|
||||
while stack:
|
||||
cur_node, path_sum = stack.pop()
|
||||
|
||||
if not cur_node.left and not cur_node.right and path_sum == targetSum:
|
||||
return True
|
||||
|
||||
if cur_node.right:
|
||||
stack.append((cur_node.right, path_sum + cur_node.right.val))
|
||||
|
||||
if cur_node.left:
|
||||
stack.append((cur_node.left, path_sum + cur_node.left.val))
|
||||
|
||||
return False
|
||||
```
|
||||
0113.路径总和-ii
|
||||
|
||||
**递归**
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
@ -453,35 +483,36 @@ class Solution:
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
//递归法
|
||||
class Solution:
|
||||
def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
|
||||
path=[]
|
||||
res=[]
|
||||
def pathes(root,targetSum):
|
||||
if (not root.left) and (not root.right) and targetSum == 0: // 遇到叶子节点,并且计数为0
|
||||
res.append(path[:]) //找到一种路径,记录到res中,注意必须是path[:]而不是path
|
||||
return
|
||||
if (not root.left) and (not root.right):return // 遇到叶子节点直接返回
|
||||
if root.left: //左
|
||||
targetSum -= root.left.val
|
||||
path.append(root.left.val) //递归前记录节点
|
||||
pathes(root.left,targetSum) //递归
|
||||
targetSum += root.left.val //回溯
|
||||
path.pop() //回溯
|
||||
if root.right: //右
|
||||
targetSum -= root.right.val
|
||||
path.append(root.right.val) //递归前记录节点
|
||||
pathes(root.right,targetSum) //递归
|
||||
targetSum += root.right.val //回溯
|
||||
path.pop() //回溯
|
||||
return
|
||||
|
||||
if root == None:return [] //处理空TreeNode
|
||||
else:
|
||||
path.append(root.val) //首先处理根节点
|
||||
pathes(root,targetSum-root.val)
|
||||
return res
|
||||
|
||||
def traversal(cur_node, remain):
|
||||
if not cur_node.left and not cur_node.right and remain == 0:
|
||||
result.append(path[:])
|
||||
return
|
||||
|
||||
if not cur_node.left and not cur_node.right: return
|
||||
|
||||
if cur_node.left:
|
||||
path.append(cur_node.left.val)
|
||||
remain -= cur_node.left.val
|
||||
traversal(cur_node.left, remain)
|
||||
path.pop()
|
||||
remain += cur_node.left.val
|
||||
|
||||
if cur_node.right:
|
||||
path.append(cur_node.right.val)
|
||||
remain -= cur_node.right.val
|
||||
traversal(cur_node.right, remain)
|
||||
path.pop()
|
||||
remain += cur_node.right.val
|
||||
|
||||
result, path = [], []
|
||||
if not root:
|
||||
return []
|
||||
path.append(root.val)
|
||||
traversal(root, targetSum - root.val)
|
||||
return result
|
||||
```
|
||||
|
||||
Go:
|
||||
|
@ -313,6 +313,26 @@ func max(a,b int)int {
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
const maxProfit = prices => {
|
||||
const len = prices.length;
|
||||
// 创建dp数组
|
||||
const dp = new Array(len).fill([0, 0]);
|
||||
// dp数组初始化
|
||||
dp[0] = [-prices[0], 0];
|
||||
for (let i = 1; i < len; i++) {
|
||||
// 更新dp[i]
|
||||
dp[i] = [
|
||||
Math.max(dp[i - 1][0], -prices[i]),
|
||||
Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0]),
|
||||
];
|
||||
}
|
||||
return dp[len - 1][1];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
<p align="center">
|
||||
<a href="https://mp.weixin.qq.com/s/RsdcQ9umo09R6cfnwXZlrQ"><img src="https://img.shields.io/badge/PDF下载-代码随想录-blueviolet" alt=""></a>
|
||||
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
|
||||
@ -63,6 +62,7 @@ public:
|
||||
## 方法二
|
||||
|
||||
把链表放进双向队列,然后通过双向队列一前一后弹出数据,来构造新的链表。这种方法比操作数组容易一些,不用双指针模拟一前一后了
|
||||
|
||||
```C++
|
||||
class Solution {
|
||||
public:
|
||||
@ -176,6 +176,51 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
public class ReorderList {
|
||||
public void reorderList(ListNode head) {
|
||||
ListNode fast = head, slow = head;
|
||||
//求出中点
|
||||
while (fast.next != null && fast.next.next != null) {
|
||||
slow = slow.next;
|
||||
fast = fast.next.next;
|
||||
}
|
||||
//right就是右半部分 12345 就是45 1234 就是34
|
||||
ListNode right = slow.next;
|
||||
//断开左部分和右部分
|
||||
slow.next = null;
|
||||
//反转右部分 right就是反转后右部分的起点
|
||||
right = reverseList(right);
|
||||
//左部分的起点
|
||||
ListNode left = head;
|
||||
//进行左右部分来回连接
|
||||
//这里左部分的节点个数一定大于等于右部分的节点个数 因此只判断right即可
|
||||
while (right != null) {
|
||||
ListNode curLeft = left.next;
|
||||
left.next = right;
|
||||
left = curLeft;
|
||||
|
||||
ListNode curRight = right.next;
|
||||
right.next = left;
|
||||
right = curRight;
|
||||
}
|
||||
}
|
||||
|
||||
public ListNode reverseList(ListNode head) {
|
||||
ListNode headNode = new ListNode(0);
|
||||
ListNode cur = head;
|
||||
ListNode next = null;
|
||||
while (cur != null) {
|
||||
next = cur.next;
|
||||
cur.next = headNode.next;
|
||||
headNode.next = cur;
|
||||
cur = next;
|
||||
}
|
||||
return headNode.next;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
Go:
|
||||
@ -183,8 +228,10 @@ Go:
|
||||
JavaScript:
|
||||
|
||||
-----------------------
|
||||
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||
|
||||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
输出:12
|
||||
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
|
||||
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
|
||||
|
||||
|
||||
|
||||
提示:
|
||||
|
||||
@ -175,6 +175,22 @@ func max(a, b int) int {
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
const rob = nums => {
|
||||
// 数组长度
|
||||
const len = nums.length;
|
||||
// dp数组初始化
|
||||
const dp = [nums[0], Math.max(nums[0], nums[1])];
|
||||
// 从下标2开始遍历
|
||||
for (let i = 2; i < len; i++) {
|
||||
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
|
||||
}
|
||||
return dp[len - 1];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -68,6 +68,25 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public boolean isIsomorphic(String s, String t) {
|
||||
Map<Character, Character> map1 = new HashMap<>();
|
||||
Map<Character, Character> map2 = new HashMap<>();
|
||||
for (int i = 0, j = 0; i < s.length(); i++, j++) {
|
||||
if (!map1.containsKey(s.charAt(i))) {
|
||||
map1.put(s.charAt(i), t.charAt(j)); // map1保存 s[i] 到 t[j]的映射
|
||||
}
|
||||
if (!map2.containsKey(t.charAt(j))) {
|
||||
map2.put(t.charAt(j), s.charAt(i)); // map2保存 t[j] 到 s[i]的映射
|
||||
}
|
||||
// 无法映射,返回 false
|
||||
if (map1.get(s.charAt(i)) != t.charAt(j) || map2.get(t.charAt(j)) != s.charAt(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
|
@ -275,7 +275,50 @@ var reverseList = function(head) {
|
||||
};
|
||||
```
|
||||
|
||||
Ruby:
|
||||
|
||||
```ruby
|
||||
# 双指针
|
||||
# Definition for singly-linked list.
|
||||
# class ListNode
|
||||
# attr_accessor :val, :next
|
||||
# def initialize(val = 0, _next = nil)
|
||||
# @val = val
|
||||
# @next = _next
|
||||
# end
|
||||
# end
|
||||
def reverse_list(head)
|
||||
# return nil if head.nil? # 循环判断条件亦能起到相同作用因此不必单独判断
|
||||
cur, per = head, nil
|
||||
until cur.nil?
|
||||
tem = cur.next
|
||||
cur.next = per
|
||||
per = cur
|
||||
cur = tem
|
||||
end
|
||||
per
|
||||
end
|
||||
|
||||
# 递归
|
||||
# Definition for singly-linked list.
|
||||
# class ListNode
|
||||
# attr_accessor :val, :next
|
||||
# def initialize(val = 0, _next = nil)
|
||||
# @val = val
|
||||
# @next = _next
|
||||
# end
|
||||
# end
|
||||
def reverse_list(head)
|
||||
reverse(nil, head)
|
||||
end
|
||||
|
||||
def reverse(pre, cur)
|
||||
return pre if cur.nil?
|
||||
tem = cur.next
|
||||
cur.next = pre
|
||||
reverse(cur, tem) # 通过递归实现双指针法中的更新操作
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -384,7 +384,7 @@ func (this *MyQueue) Peek() int {
|
||||
func (this *MyQueue) Empty() bool {
|
||||
return len(this.stack) == 0 && len(this.back) == 0
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
javaScript:
|
||||
|
||||
@ -442,8 +442,6 @@ MyQueue.prototype.empty = function() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||
|
@ -368,7 +368,32 @@ class Solution:
|
||||
return (val1, val2)
|
||||
```
|
||||
|
||||
Go:
|
||||
JavaScript:
|
||||
|
||||
> 动态规划
|
||||
|
||||
```javascript
|
||||
const rob = root => {
|
||||
// 后序遍历函数
|
||||
const postOrder = node => {
|
||||
// 递归出口
|
||||
if (!node) return [0, 0];
|
||||
// 遍历左子树
|
||||
const left = postOrder(node.left);
|
||||
// 遍历右子树
|
||||
const right = postOrder(node.right);
|
||||
// 不偷当前节点,左右子节点都可以偷或不偷,取最大值
|
||||
const DoNot = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
|
||||
// 偷当前节点,左右子节点只能不偷
|
||||
const Do = node.val + left[0] + right[0];
|
||||
// [不偷,偷]
|
||||
return [DoNot, Do];
|
||||
};
|
||||
const res = postOrder(root);
|
||||
// 返回最大值
|
||||
return Math.max(...res);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -190,6 +190,101 @@ class Solution:
|
||||
Go:
|
||||
|
||||
|
||||
javaScript:
|
||||
```js
|
||||
/**
|
||||
* @param {number[]} nums
|
||||
* @param {number} k
|
||||
* @return {number[]}
|
||||
*/
|
||||
var topKFrequent = function(nums, k) {
|
||||
const map = new Map();
|
||||
|
||||
for(const num of nums) {
|
||||
map.set(num, (map.get(num) || 0) + 1);
|
||||
}
|
||||
|
||||
// 创建小顶堆
|
||||
const priorityQueue = new PriorityQueue((a, b) => a[1] - b[1]);
|
||||
|
||||
// entry 是一个长度为2的数组,0位置存储key,1位置存储value
|
||||
for (const entry of map.entries()) {
|
||||
priorityQueue.push(entry);
|
||||
if (priorityQueue.size() > k) {
|
||||
priorityQueue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
const ret = [];
|
||||
|
||||
for(let i = priorityQueue.size() - 1; i >= 0; i--) {
|
||||
ret[i] = priorityQueue.pop()[0];
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
function PriorityQueue(compareFn) {
|
||||
this.compareFn = compareFn;
|
||||
this.queue = [];
|
||||
}
|
||||
|
||||
// 添加
|
||||
PriorityQueue.prototype.push = function(item) {
|
||||
this.queue.push(item);
|
||||
let index = this.queue.length - 1;
|
||||
let parent = Math.floor((index - 1) / 2);
|
||||
// 上浮
|
||||
while(parent >= 0 && this.compare(parent, index) > 0) {
|
||||
// 交换
|
||||
[this.queue[index], this.queue[parent]] = [this.queue[parent], this.queue[index]];
|
||||
index = parent;
|
||||
parent = Math.floor((index - 1) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取堆顶元素并移除
|
||||
PriorityQueue.prototype.pop = function() {
|
||||
const ret = this.queue[0];
|
||||
|
||||
// 把最后一个节点移到堆顶
|
||||
this.queue[0] = this.queue.pop();
|
||||
|
||||
let index = 0;
|
||||
// 左子节点下标,left + 1 就是右子节点下标
|
||||
let left = 1;
|
||||
let selectedChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
|
||||
|
||||
// 下沉
|
||||
while(selectedChild !== undefined && this.compare(index, selectedChild) > 0) {
|
||||
// 交换
|
||||
[this.queue[index], this.queue[selectedChild]] = [this.queue[selectedChild], this.queue[index]];
|
||||
index = selectedChild;
|
||||
left = 2 * index + 1;
|
||||
selectedChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PriorityQueue.prototype.size = function() {
|
||||
return this.queue.length;
|
||||
}
|
||||
|
||||
// 使用传入的 compareFn 比较两个位置的元素
|
||||
PriorityQueue.prototype.compare = function(index1, index2) {
|
||||
if (this.queue[index1] === undefined) {
|
||||
return 1;
|
||||
}
|
||||
if (this.queue[index2] === undefined) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return this.compareFn(this.queue[index1], this.queue[index2]);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -180,7 +180,30 @@ class Solution:
|
||||
return False
|
||||
```
|
||||
|
||||
Go:
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
const isSubsequence = (s, t) => {
|
||||
// s、t的长度
|
||||
const [m, n] = [s.length, t.length];
|
||||
// dp全初始化为0
|
||||
const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0));
|
||||
for (let i = 1; i <= m; i++) {
|
||||
for (let j = 1; j <= n; j++) {
|
||||
// 更新dp[i][j],两种情况
|
||||
if (s[i - 1] === t[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = dp[i][j - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 遍历结束,判断dp右下角的数是否等于s的长度
|
||||
return dp[m][n] === m ? true : false;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -205,25 +205,51 @@ class Solution {
|
||||
|
||||
|
||||
Python:
|
||||
```Python
|
||||
|
||||
**递归**
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
```python
|
||||
class Solution:
|
||||
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||
self.res=0
|
||||
def areleftleaves(root):
|
||||
if not root:return
|
||||
if root.left and (not root.left.left) and (not root.left.right):self.res+=root.left.val
|
||||
areleftleaves(root.left)
|
||||
areleftleaves(root.right)
|
||||
areleftleaves(root)
|
||||
return self.res
|
||||
if not root:
|
||||
return 0
|
||||
|
||||
left_left_leaves_sum = self.sumOfLeftLeaves(root.left) # 左
|
||||
right_left_leaves_sum = self.sumOfLeftLeaves(root.right) # 右
|
||||
|
||||
cur_left_leaf_val = 0
|
||||
if root.left and not root.left.left and not root.left.right:
|
||||
cur_left_leaf_val = root.left.val # 中
|
||||
|
||||
return cur_left_leaf_val + left_left_leaves_sum + right_left_leaves_sum
|
||||
```
|
||||
|
||||
**迭代**
|
||||
```python
|
||||
class Solution:
|
||||
def sumOfLeftLeaves(self, root: TreeNode) -> int:
|
||||
"""
|
||||
Idea: Each time check current node's left node.
|
||||
If current node don't have one, skip it.
|
||||
"""
|
||||
stack = []
|
||||
if root:
|
||||
stack.append(root)
|
||||
res = 0
|
||||
|
||||
while stack:
|
||||
# 每次都把当前节点的左节点加进去.
|
||||
cur_node = stack.pop()
|
||||
if cur_node.left and not cur_node.left.left and not cur_node.left.right:
|
||||
res += cur_node.left.val
|
||||
|
||||
if cur_node.left:
|
||||
stack.append(cur_node.left)
|
||||
if cur_node.right:
|
||||
stack.append(cur_node.right)
|
||||
|
||||
return res
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
> 递归法
|
||||
|
@ -274,27 +274,51 @@ class Solution {
|
||||
|
||||
|
||||
Python:
|
||||
|
||||
**递归 - 回溯**
|
||||
```python
|
||||
//递归法
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
# def __init__(self, val=0, left=None, right=None):
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def findBottomLeftValue(self, root: TreeNode) -> int:
|
||||
depth=0
|
||||
self.res=[]
|
||||
def level(root,depth):
|
||||
if not root:return
|
||||
if depth==len(self.res):
|
||||
self.res.append([])
|
||||
self.res[depth].append(root.val)
|
||||
level(root.left,depth+1)
|
||||
level(root.right,depth+1)
|
||||
level(root,depth)
|
||||
return self.res[-1][0]
|
||||
max_depth = -float("INF")
|
||||
leftmost_val = 0
|
||||
|
||||
def __traverse(root, cur_depth):
|
||||
nonlocal max_depth, leftmost_val
|
||||
if not root.left and not root.right:
|
||||
if cur_depth > max_depth:
|
||||
max_depth = cur_depth
|
||||
leftmost_val = root.val
|
||||
if root.left:
|
||||
cur_depth += 1
|
||||
__traverse(root.left, cur_depth)
|
||||
cur_depth -= 1
|
||||
if root.right:
|
||||
cur_depth += 1
|
||||
__traverse(root.right, cur_depth)
|
||||
cur_depth -= 1
|
||||
|
||||
__traverse(root, 0)
|
||||
return leftmost_val
|
||||
```
|
||||
**迭代 - 层序遍历**
|
||||
```python
|
||||
class Solution:
|
||||
def findBottomLeftValue(self, root: TreeNode) -> int:
|
||||
queue = deque()
|
||||
if root:
|
||||
queue.append(root)
|
||||
result = 0
|
||||
while queue:
|
||||
q_len = len(queue)
|
||||
for i in range(q_len):
|
||||
if i == 0:
|
||||
result = queue[i].val
|
||||
cur = queue.popleft()
|
||||
if cur.left:
|
||||
queue.append(cur.left)
|
||||
if cur.right:
|
||||
queue.append(cur.right)
|
||||
return result
|
||||
```
|
||||
Go:
|
||||
|
||||
|
@ -312,6 +312,8 @@ class Solution {
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
**递归法 - 前序遍历**
|
||||
```python
|
||||
# Definition for a binary tree node.
|
||||
# class TreeNode:
|
||||
@ -319,41 +321,57 @@ Python:
|
||||
# self.val = val
|
||||
# self.left = left
|
||||
# self.right = right
|
||||
# 递归法*前序遍历
|
||||
class Solution:
|
||||
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
if not root1: return root2 // 如果t1为空,合并之后就应该是t2
|
||||
if not root2: return root1 // 如果t2为空,合并之后就应该是t1
|
||||
root1.val = root1.val + root2.val //中
|
||||
root1.left = self.mergeTrees(root1.left , root2.left) //左
|
||||
root1.right = self.mergeTrees(root1.right , root2.right) //右
|
||||
return root1 //root1修改了结构和数值
|
||||
# 递归终止条件:
|
||||
# 但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.
|
||||
if not root1:
|
||||
return root2
|
||||
if not root2:
|
||||
return root1
|
||||
# 上面的递归终止条件保证了代码执行到这里root1, root2都非空.
|
||||
root1.val += root2.val # 中
|
||||
root1.left = self.mergeTrees(root1.left, root2.left) #左
|
||||
root1.right = self.mergeTrees(root1.right, root2.right) # 右
|
||||
|
||||
return root1 # ⚠️ 注意: 本题我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间.
|
||||
|
||||
# 迭代法-覆盖原来的树
|
||||
```
|
||||
|
||||
**迭代法**
|
||||
```python
|
||||
class Solution:
|
||||
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
|
||||
if not root1: return root2
|
||||
if not root2: return root1
|
||||
# 迭代,将树2覆盖到树1
|
||||
queue1 = [root1]
|
||||
queue2 = [root2]
|
||||
root = root1
|
||||
while queue1 and queue2:
|
||||
root1 = queue1.pop(0)
|
||||
root2 = queue2.pop(0)
|
||||
root1.val += root2.val
|
||||
if not root1.left: # 如果树1左儿子不存在,则覆盖后树1的左儿子为树2的左儿子
|
||||
root1.left = root2.left
|
||||
elif root1.left and root2.left:
|
||||
queue1.append(root1.left)
|
||||
queue2.append(root2.left)
|
||||
if not root1:
|
||||
return root2
|
||||
if not root2:
|
||||
return root1
|
||||
|
||||
if not root1.right: # 同理,处理右儿子
|
||||
root1.right = root2.right
|
||||
elif root1.right and root2.right:
|
||||
queue1.append(root1.right)
|
||||
queue2.append(root2.right)
|
||||
return root
|
||||
queue = deque()
|
||||
queue.append(root1)
|
||||
queue.append(root2)
|
||||
|
||||
while queue:
|
||||
node1 = queue.popleft()
|
||||
node2 = queue.popleft()
|
||||
# 更新queue
|
||||
# 只有两个节点都有左节点时, 再往queue里面放.
|
||||
if node1.left and node2.left:
|
||||
queue.append(node1.left)
|
||||
queue.append(node2.left)
|
||||
# 只有两个节点都有右节点时, 再往queue里面放.
|
||||
if node1.right and node2.right:
|
||||
queue.append(node1.right)
|
||||
queue.append(node2.right)
|
||||
|
||||
# 更新当前节点. 同时改变当前节点的左右孩子.
|
||||
node1.val += node2.val
|
||||
if not node1.left and node2.left:
|
||||
node1.left = node2.left
|
||||
if not node1.right and node2.right:
|
||||
node1.right = node2.right
|
||||
|
||||
return root1
|
||||
```
|
||||
|
||||
Go:
|
||||
|
@ -71,21 +71,84 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
// 时间复杂度:O(n)
|
||||
// 空间复杂度:如果采用 toCharArray,则是 O(n);如果使用 charAt,则是 O(1)
|
||||
class Solution {
|
||||
public boolean judgeCircle(String moves) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
for (char c : moves.toCharArray()) {
|
||||
if (c == 'U') y++;
|
||||
if (c == 'D') y--;
|
||||
if (c == 'L') x++;
|
||||
if (c == 'R') x--;
|
||||
}
|
||||
return x == 0 && y == 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
|
||||
```python
|
||||
# 时间复杂度:O(n)
|
||||
# 空间复杂度:O(1)
|
||||
class Solution:
|
||||
def judgeCircle(self, moves: str) -> bool:
|
||||
x = 0 # 记录当前位置
|
||||
y = 0
|
||||
for i in range(len(moves)):
|
||||
if (moves[i] == 'U'):
|
||||
y += 1
|
||||
if (moves[i] == 'D'):
|
||||
y -= 1
|
||||
if (moves[i] == 'L'):
|
||||
x += 1
|
||||
if (moves[i] == 'R'):
|
||||
x -= 1
|
||||
return x == 0 and y == 0
|
||||
```
|
||||
|
||||
## Go
|
||||
|
||||
```go
|
||||
func judgeCircle(moves string) bool {
|
||||
x := 0
|
||||
y := 0
|
||||
for i := 0; i < len(moves); i++ {
|
||||
if moves[i] == 'U' {
|
||||
y++
|
||||
}
|
||||
if moves[i] == 'D' {
|
||||
y--
|
||||
}
|
||||
if moves[i] == 'L' {
|
||||
x++
|
||||
}
|
||||
if moves[i] == 'R' {
|
||||
x--
|
||||
}
|
||||
}
|
||||
return x == 0 && y == 0;
|
||||
}
|
||||
```
|
||||
|
||||
## JavaScript
|
||||
|
||||
```js
|
||||
// 时间复杂度:O(n)
|
||||
// 空间复杂度:O(1)
|
||||
var judgeCircle = function(moves) {
|
||||
var x = 0; // 记录当前位置
|
||||
var y = 0;
|
||||
for (var i = 0; i < moves.length; i++) {
|
||||
if (moves[i] == 'U') y++;
|
||||
if (moves[i] == 'D') y--;
|
||||
if (moves[i] == 'L') x++;
|
||||
if (moves[i] == 'R') x--;
|
||||
}
|
||||
return x == 0 && y == 0;
|
||||
};
|
||||
```
|
||||
|
||||
-----------------------
|
||||
|
@ -220,9 +220,18 @@ Python:
|
||||
# self.right = right
|
||||
class Solution:
|
||||
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if not root or root.val == val: return root //为空或者已经找到都是直接返回root,所以合并了
|
||||
if root.val > val: return self.searchBST(root.left,val) //注意一定要加return
|
||||
else: return self.searchBST(root.right,val)
|
||||
# 为什么要有返回值:
|
||||
# 因为搜索到目标节点就要立即return,
|
||||
# 这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。
|
||||
|
||||
if not root or root.val == val:
|
||||
return root
|
||||
|
||||
if root.val > val:
|
||||
return self.searchBST(root.left, val)
|
||||
|
||||
if root.val < val:
|
||||
return self.searchBST(root.right, val)
|
||||
|
||||
```
|
||||
|
||||
|
@ -255,7 +255,7 @@ class Solution {
|
||||
|
||||
Python:
|
||||
|
||||
递归法
|
||||
**递归法** - 有返回值
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
@ -268,7 +268,63 @@ class Solution:
|
||||
root.left = self.insertIntoBST(root.left, val) # 递归创建左子树
|
||||
return root
|
||||
```
|
||||
**递归法** - 无返回值
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if not root:
|
||||
return TreeNode(val)
|
||||
parent = None
|
||||
def __traverse(cur: TreeNode, val: int) -> None:
|
||||
# 在函数运行的同时把新节点插入到该被插入的地方.
|
||||
nonlocal parent
|
||||
if not cur:
|
||||
new_node = TreeNode(val)
|
||||
if parent.val < val:
|
||||
parent.right = new_node
|
||||
else:
|
||||
parent.left = new_node
|
||||
return
|
||||
|
||||
parent = cur # 重点: parent的作用只有运行到上面if not cur:才会发挥出来.
|
||||
if cur.val < val:
|
||||
__traverse(cur.right, val)
|
||||
else:
|
||||
__traverse(cur.left, val)
|
||||
return
|
||||
__traverse(root, val)
|
||||
return root
|
||||
```
|
||||
**迭代法**
|
||||
与无返回值的递归函数的思路大体一致
|
||||
```python
|
||||
class Solution:
|
||||
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
|
||||
if not root:
|
||||
return TreeNode(val)
|
||||
parent = None
|
||||
cur = root
|
||||
|
||||
# 用while循环不断地找新节点的parent
|
||||
while cur:
|
||||
if cur.val < val:
|
||||
parent = cur
|
||||
cur = cur.right
|
||||
elif cur.val > val:
|
||||
parent = cur
|
||||
cur = cur.left
|
||||
|
||||
# 运行到这意味着已经跳出上面的while循环,
|
||||
# 同时意味着新节点的parent已经被找到.
|
||||
# parent已被找到, 新节点已经ready. 把两个节点黏在一起就好了.
|
||||
if parent.val > val:
|
||||
parent.left = TreeNode(val)
|
||||
else:
|
||||
parent.right = TreeNode(val)
|
||||
|
||||
return root
|
||||
|
||||
```
|
||||
|
||||
Go:
|
||||
|
||||
|
@ -235,8 +235,6 @@ class Solution:
|
||||
return -1
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Go:**
|
||||
|
||||
(版本一)左闭右闭区间
|
||||
@ -279,7 +277,7 @@ func search(nums []int, target int) int {
|
||||
}
|
||||
```
|
||||
|
||||
**javaScript:**
|
||||
**JavaScript:**
|
||||
|
||||
```js
|
||||
|
||||
@ -316,7 +314,97 @@ var search = function(nums, target) {
|
||||
|
||||
```
|
||||
|
||||
**Ruby:**
|
||||
|
||||
```ruby
|
||||
# (版本一)左闭右闭区间
|
||||
|
||||
def search(nums, target)
|
||||
left, right = 0, nums.length - 1
|
||||
while left <= right # 由于定义target在一个在左闭右闭的区间里,因此极限情况下存在left==right
|
||||
middle = (left + right) / 2
|
||||
if nums[middle] > target
|
||||
right = middle - 1
|
||||
elsif nums[middle] < target
|
||||
left = middle + 1
|
||||
else
|
||||
return middle # return兼具返回与跳出循环的作用
|
||||
end
|
||||
end
|
||||
-1
|
||||
end
|
||||
|
||||
# (版本二)左闭右开区间
|
||||
|
||||
def search(nums, target)
|
||||
left, right = 0, nums.length
|
||||
while left < right # 由于定义target在一个在左闭右开的区间里,因此极限情况下right=left+1
|
||||
middle = (left + right) / 2
|
||||
if nums[middle] > target
|
||||
right = middle
|
||||
elsif nums[middle] < target
|
||||
left = middle + 1
|
||||
else
|
||||
return middle
|
||||
end
|
||||
end
|
||||
-1
|
||||
end
|
||||
```
|
||||
|
||||
**Swift:**
|
||||
|
||||
```swift
|
||||
// (版本一)左闭右闭区间
|
||||
func search(nums: [Int], target: Int) -> Int {
|
||||
// 1. 先定义区间。这里的区间是[left, right]
|
||||
var left = 0
|
||||
var right = nums.count - 1
|
||||
|
||||
while left <= right {// 因为taeget是在[left, right]中,包括两个边界值,所以这里的left == right是有意义的
|
||||
// 2. 计算区间中间的下标(如果left、right都比较大的情况下,left + right就有可能会溢出)
|
||||
// let middle = (left + right) / 2
|
||||
// 防溢出:
|
||||
let middle = left + (right - left) / 2
|
||||
|
||||
// 3. 判断
|
||||
if target < nums[middle] {
|
||||
// 当目标在区间左侧,就需要更新右边的边界值,新区间为[left, middle - 1]
|
||||
right = middle - 1
|
||||
} else if target > nums[middle] {
|
||||
// 当目标在区间右侧,就需要更新左边的边界值,新区间为[middle + 1, right]
|
||||
left = middle + 1
|
||||
} else {
|
||||
// 当目标就是在中间,则返回中间值的下标
|
||||
return middle
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到目标,则返回-1
|
||||
return -1
|
||||
}
|
||||
|
||||
// (版本二)左闭右开区间
|
||||
func search(nums: [Int], target: Int) -> Int {
|
||||
var left = 0
|
||||
var right = nums.count
|
||||
|
||||
while left < right {
|
||||
let middle = left + ((right - left) >> 1)
|
||||
|
||||
if target < nums[middle] {
|
||||
right = middle
|
||||
} else if target > nums[middle] {
|
||||
left = middle + 1
|
||||
} else {
|
||||
return middle
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -154,7 +154,129 @@ private:
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
C:
|
||||
```C
|
||||
typedef struct {
|
||||
int val;
|
||||
struct MyLinkedList* next;
|
||||
}MyLinkedList;
|
||||
|
||||
/** Initialize your data structure here. */
|
||||
|
||||
MyLinkedList* myLinkedListCreate() {
|
||||
//这个题必须用虚拟头指针,参数都是一级指针,头节点确定后没法改指向了!!!
|
||||
MyLinkedList* head = (MyLinkedList *)malloc(sizeof (MyLinkedList));
|
||||
head->next = NULL;
|
||||
return head;
|
||||
}
|
||||
|
||||
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
|
||||
int myLinkedListGet(MyLinkedList* obj, int index) {
|
||||
MyLinkedList *cur = obj->next;
|
||||
for (int i = 0; cur != NULL; i++){
|
||||
if (i == index){
|
||||
return cur->val;
|
||||
}
|
||||
else{
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
|
||||
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
|
||||
MyLinkedList *nhead = (MyLinkedList *)malloc(sizeof (MyLinkedList));
|
||||
nhead->val = val;
|
||||
nhead->next = obj->next;
|
||||
obj->next = nhead;
|
||||
|
||||
}
|
||||
|
||||
/** Append a node of value val to the last element of the linked list. */
|
||||
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
|
||||
MyLinkedList *cur = obj;
|
||||
while(cur->next != NULL){
|
||||
cur = cur->next;
|
||||
}
|
||||
MyLinkedList *ntail = (MyLinkedList *)malloc(sizeof (MyLinkedList));
|
||||
ntail->val = val;
|
||||
ntail->next = NULL;
|
||||
cur->next = ntail;
|
||||
}
|
||||
|
||||
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
|
||||
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
|
||||
if (index == 0){
|
||||
myLinkedListAddAtHead(obj, val);
|
||||
return;
|
||||
}
|
||||
MyLinkedList *cur = obj->next;
|
||||
for (int i = 1 ;cur != NULL; i++){
|
||||
if (i == index){
|
||||
MyLinkedList* newnode = (MyLinkedList *)malloc(sizeof (MyLinkedList));
|
||||
newnode->val = val;
|
||||
newnode->next = cur->next;
|
||||
cur->next = newnode;
|
||||
return;
|
||||
}
|
||||
else{
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete the index-th node in the linked list, if the index is valid. */
|
||||
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
|
||||
if (index == 0){
|
||||
MyLinkedList *tmp = obj->next;
|
||||
if (tmp != NULL){
|
||||
obj->next = tmp->next;
|
||||
free(tmp)
|
||||
}
|
||||
return;
|
||||
}
|
||||
MyLinkedList *cur = obj->next;
|
||||
for (int i = 1 ;cur != NULL && cur->next != NULL; i++){
|
||||
if (i == index){
|
||||
MyLinkedList *tmp = cur->next;
|
||||
if (tmp != NULL) {
|
||||
cur->next = tmp->next;
|
||||
free(tmp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else{
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void myLinkedListFree(MyLinkedList* obj) {
|
||||
while(obj != NULL){
|
||||
MyLinkedList *tmp = obj;
|
||||
obj = obj->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Your MyLinkedList struct will be instantiated and called as such:
|
||||
* MyLinkedList* obj = myLinkedListCreate();
|
||||
* int param_1 = myLinkedListGet(obj, index);
|
||||
|
||||
* myLinkedListAddAtHead(obj, val);
|
||||
|
||||
* myLinkedListAddAtTail(obj, val);
|
||||
|
||||
* myLinkedListAddAtIndex(obj, index, val);
|
||||
|
||||
* myLinkedListDeleteAtIndex(obj, index);
|
||||
|
||||
* myLinkedListFree(obj);
|
||||
*/
|
||||
```
|
||||
|
||||
Java:
|
||||
```Java
|
||||
|
@ -252,6 +252,33 @@ func findLength(A []int, B []int) int {
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
> 动态规划
|
||||
|
||||
```javascript
|
||||
const findLength = (A, B) => {
|
||||
// A、B数组的长度
|
||||
const [m, n] = [A.length, B.length];
|
||||
// dp数组初始化,都初始化为0
|
||||
const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0));
|
||||
// 初始化最大长度为0
|
||||
let res = 0;
|
||||
for (let i = 1; i <= m; i++) {
|
||||
for (let j = 1; j <= n; j++) {
|
||||
// 遇到A[i - 1] === B[j - 1],则更新dp数组
|
||||
if (A[i - 1] === B[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
}
|
||||
// 更新res
|
||||
res = dp[i][j] > res ? dp[i][j] : res;
|
||||
}
|
||||
}
|
||||
// 遍历完成,返回res
|
||||
return res;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -67,6 +67,24 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int pivotIndex(int[] nums) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
sum += nums[i]; // 总和
|
||||
}
|
||||
int leftSum = 0;
|
||||
int rightSum = 0;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
leftSum += nums[i];
|
||||
rightSum = sum - leftSum + nums[i]; // leftSum 里面已经有 nums[i],多减了一次,所以加上
|
||||
if (leftSum == rightSum) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // 不存在
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
@ -90,4 +108,3 @@ public:
|
||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。
|
||||
|
||||
注意:如果对空文本输入退格字符,文本继续为空。
|
||||
|
||||
|
||||
示例 1:
|
||||
* 输入:S = "ab#c", T = "ad#c"
|
||||
* 输出:true
|
||||
@ -160,6 +160,32 @@ public:
|
||||
|
||||
Java:
|
||||
|
||||
```java
|
||||
// 普通方法(使用栈的思路)
|
||||
class Solution {
|
||||
public boolean backspaceCompare(String s, String t) {
|
||||
StringBuilder ssb = new StringBuilder(); // 模拟栈
|
||||
StringBuilder tsb = new StringBuilder(); // 模拟栈
|
||||
// 分别处理两个 String
|
||||
for (char c : s.toCharArray()) {
|
||||
if (c != '#') {
|
||||
ssb.append(c); // 模拟入栈
|
||||
} else if (ssb.length() > 0){ // 栈非空才能弹栈
|
||||
ssb.deleteCharAt(ssb.length() - 1); // 模拟弹栈
|
||||
}
|
||||
}
|
||||
for (char c : t.toCharArray()) {
|
||||
if (c != '#') {
|
||||
tsb.append(c); // 模拟入栈
|
||||
} else if (tsb.length() > 0){ // 栈非空才能弹栈
|
||||
tsb.deleteCharAt(tsb.length() - 1); // 模拟弹栈
|
||||
}
|
||||
}
|
||||
return ssb.toString().equals(tsb.toString());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
Go:
|
||||
|
@ -120,6 +120,31 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
// 方法一
|
||||
class Solution {
|
||||
public int[] sortArrayByParityII(int[] nums) {
|
||||
// 分别存放 nums 中的奇数、偶数
|
||||
int len = nums.length;
|
||||
int evenIndex = 0;
|
||||
int oddIndex = 0;
|
||||
int[] even = new int[len / 2];
|
||||
int[] odd = new int[len / 2];
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (nums[i] % 2 == 0) {
|
||||
even[evenIndex++] = nums[i];
|
||||
} else {
|
||||
odd[oddIndex++] = nums[i];
|
||||
}
|
||||
}
|
||||
// 把奇偶数组重新存回 nums
|
||||
int index = 0;
|
||||
for (int i = 0; i < even.length; i++) {
|
||||
nums[index++] = even[i];
|
||||
nums[index++] = odd[i];
|
||||
}
|
||||
return nums;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Python
|
||||
@ -143,4 +168,3 @@ public:
|
||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
||||
|
||||
|
||||
|
@ -169,6 +169,46 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
javaScript
|
||||
```js
|
||||
var commonChars = function (words) {
|
||||
let res = []
|
||||
let size = 26
|
||||
let firstHash = new Array(size)
|
||||
for (let i = 0; i < size; i++) { // 初始化 hash 数组
|
||||
firstHash[i] = 0
|
||||
}
|
||||
|
||||
let a = "a".charCodeAt()
|
||||
let firstWord = words[0]
|
||||
for (let i = 0; i < firstWord.length; i++) { // 第 0 个单词的统计
|
||||
let idx = firstWord[i].charCodeAt()
|
||||
firstHash[idx - a] += 1
|
||||
}
|
||||
|
||||
for (let i = 1; i < words.length; i++) { // 1-n 个单词统计
|
||||
let otherHash = new Array(size)
|
||||
for (let i = 0; i < size; i++) { // 初始化 hash 数组
|
||||
otherHash[i] = 0
|
||||
}
|
||||
|
||||
for (let j = 0; j < words[i].length; j++) {
|
||||
let idx = words[i][j].charCodeAt()
|
||||
otherHash[idx - a] += 1
|
||||
}
|
||||
for (let i = 0; i < size; i++) {
|
||||
firstHash[i] = Math.min(firstHash[i], otherHash[i])
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < size; i++) {
|
||||
while (firstHash[i] > 0) {
|
||||
res.push(String.fromCharCode(i + a))
|
||||
firstHash[i]--
|
||||
}
|
||||
}
|
||||
return res
|
||||
};
|
||||
```
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
|
@ -109,7 +109,28 @@ class Solution:
|
||||
return dp[-1][-1]
|
||||
```
|
||||
|
||||
Go:
|
||||
JavaScript:
|
||||
|
||||
```javascript
|
||||
const maxUncrossedLines = (nums1, nums2) => {
|
||||
// 两个数组长度
|
||||
const [m, n] = [nums1.length, nums2.length];
|
||||
// 创建dp数组并都初始化为0
|
||||
const dp = new Array(m + 1).fill(0).map(x => new Array(n + 1).fill(0));
|
||||
for (let i = 1; i <= m; i++) {
|
||||
for (let j = 1; j <= n; j++) {
|
||||
// 根据两种情况更新dp[i][j]
|
||||
if (nums1[i - 1] === nums2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 返回dp数组中右下角的元素
|
||||
return dp[m][n];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 nums[j] < nums[i] 。
|
||||
|
||||
以数组形式返回答案。
|
||||
|
||||
|
||||
|
||||
示例 1:
|
||||
输入:nums = [8,1,2,2,3]
|
||||
@ -35,7 +35,7 @@
|
||||
示例 3:
|
||||
输入:nums = [7,7,7,7]
|
||||
输出:[0,0,0,0]
|
||||
|
||||
|
||||
提示:
|
||||
* 2 <= nums.length <= 500
|
||||
* 0 <= nums[i] <= 100
|
||||
@ -120,8 +120,51 @@ public:
|
||||
## Java
|
||||
|
||||
```java
|
||||
/**
|
||||
* 解法一:暴力
|
||||
* 时间复杂度:O(n^2)
|
||||
* 空间复杂度:O(n)
|
||||
*/
|
||||
class Solution {
|
||||
public int[] smallerNumbersThanCurrent(int[] nums) {
|
||||
int[] res = new int[nums.length];
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
for (int j = 0; j < nums.length; j++) {
|
||||
if (nums[j] < nums[i] && j != i) { // 注意 j 不能和 i 重合
|
||||
res[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
/**
|
||||
* 优化:排序 + 哈希表
|
||||
* 时间复杂度:O(nlogn)
|
||||
* 空间复杂度:O(n)
|
||||
*/
|
||||
class Solution {
|
||||
public int[] smallerNumbersThanCurrent(int[] nums) {
|
||||
int[] res = Arrays.copyOf(nums, nums.length);
|
||||
Arrays.sort(res); // 是对 res 排序,nums 中顺序还要保持
|
||||
int[] hash = new int[101]; // 使用哈希表,记录比当前元素小的元素个数
|
||||
for (int i = res.length - 1; i >= 0; i--) { // 注意:从后向前
|
||||
hash[res[i]] = i; // 排序后,当前下标即表示比当前元素小的元素个数
|
||||
}
|
||||
// 此时 hash中保存的每一个元素数值 便是 小于这个数值的个数
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = hash[nums[i]];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Python
|
||||
|
||||
```python
|
||||
@ -143,4 +186,3 @@ public:
|
||||
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
|
||||
<div align="center"><img src=../pics/公众号.png width=450 alt=> </img></div>
|
||||
|
||||
|
||||
|
@ -222,7 +222,7 @@ Go:
|
||||
|
||||
前序遍历:
|
||||
```go
|
||||
func PreorderTraversal(root *TreeNode) (res []int) {
|
||||
func preorderTraversal(root *TreeNode) (res []int) {
|
||||
var traversal func(node *TreeNode)
|
||||
traversal = func(node *TreeNode) {
|
||||
if node == nil {
|
||||
@ -240,7 +240,7 @@ func PreorderTraversal(root *TreeNode) (res []int) {
|
||||
中序遍历:
|
||||
|
||||
```go
|
||||
func InorderTraversal(root *TreeNode) (res []int) {
|
||||
func inorderTraversal(root *TreeNode) (res []int) {
|
||||
var traversal func(node *TreeNode)
|
||||
traversal = func(node *TreeNode) {
|
||||
if node == nil {
|
||||
@ -257,7 +257,7 @@ func InorderTraversal(root *TreeNode) (res []int) {
|
||||
后序遍历:
|
||||
|
||||
```go
|
||||
func PostorderTraversal(root *TreeNode) (res []int) {
|
||||
func postorderTraversal(root *TreeNode) (res []int) {
|
||||
var traversal func(node *TreeNode)
|
||||
traversal = func(node *TreeNode) {
|
||||
if node == nil {
|
||||
|
@ -311,7 +311,38 @@ func main() {
|
||||
fmt.Println(test_CompletePack2(weight, price, 4))
|
||||
}
|
||||
```
|
||||
Javascript:
|
||||
```Javascript
|
||||
// 先遍历物品,再遍历背包容量
|
||||
function test_completePack1() {
|
||||
let weight = [1, 3, 5]
|
||||
let value = [15, 20, 30]
|
||||
let bagWeight = 4
|
||||
let dp = new Array(bagWeight + 1).fill(0)
|
||||
for(let i = 0; i <= weight.length; i++) {
|
||||
for(let j = weight[i]; j <= bagWeight; j++) {
|
||||
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i])
|
||||
}
|
||||
}
|
||||
console.log(dp)
|
||||
}
|
||||
|
||||
// 先遍历背包容量,再遍历物品
|
||||
function test_completePack2() {
|
||||
let weight = [1, 3, 5]
|
||||
let value = [15, 20, 30]
|
||||
let bagWeight = 4
|
||||
let dp = new Array(bagWeight + 1).fill(0)
|
||||
for(let j = 0; j <= bagWeight; j++) {
|
||||
for(let i = 0; i < weight.length; i++) {
|
||||
if (j >= weight[i]) {
|
||||
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(2, dp);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
Reference in New Issue
Block a user