mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 16:54:50 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -263,21 +263,38 @@ public:
|
||||
Java:
|
||||
|
||||
```java
|
||||
public int[] twoSum(int[] nums, int target) {
|
||||
int[] res = new int[2];
|
||||
if(nums == null || nums.length == 0){
|
||||
return res;
|
||||
}
|
||||
Map<Integer, Integer> map = new HashMap<>();
|
||||
for(int i = 0; i < nums.length; i++){
|
||||
int temp = target - nums[i];
|
||||
if(map.containsKey(temp)){
|
||||
res[1] = i;
|
||||
res[0] = map.get(temp);
|
||||
// 双指针 动态规划
|
||||
class Solution {
|
||||
public String longestPalindrome(String s) {
|
||||
if (s.length() == 0 || s.length() == 1) return s;
|
||||
int length = 1;
|
||||
int index = 0;
|
||||
boolean[][] palindrome = new boolean[s.length()][s.length()];
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
palindrome[i][i] = true;
|
||||
}
|
||||
map.put(nums[i], i);
|
||||
|
||||
for (int L = 2; L <= s.length(); L++) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
int j = i + L - 1;
|
||||
if (j >= s.length()) break;
|
||||
if (s.charAt(i) != s.charAt(j)) {
|
||||
palindrome[i][j] = false;
|
||||
} else {
|
||||
if (j - i < 3) {
|
||||
palindrome[i][j] = true;
|
||||
} else {
|
||||
palindrome[i][j] = palindrome[i + 1][j - 1];
|
||||
}
|
||||
}
|
||||
if (palindrome[i][j] && j - i + 1 > length) {
|
||||
length = j - i + 1;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.substring(index, index + length);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
@ -363,6 +380,34 @@ class Solution:
|
||||
Go:
|
||||
|
||||
```go
|
||||
func longestPalindrome(s string) string {
|
||||
maxLen := 0
|
||||
left := 0
|
||||
length := 0
|
||||
dp := make([][]bool, len(s))
|
||||
for i := 0; i < len(s); i++ {
|
||||
dp[i] = make([]bool,len(s))
|
||||
}
|
||||
for i := len(s)-1; i >= 0; i-- {
|
||||
for j := i; j < len(s); j++ {
|
||||
if s[i] == s[j]{
|
||||
if j-i <= 1{ // 情况一和情况二
|
||||
length = j-i
|
||||
dp[i][j]=true
|
||||
}else if dp[i+1][j-1]{ // 情况三
|
||||
length = j-i
|
||||
dp[i][j] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if length > maxLen {
|
||||
maxLen = length
|
||||
left = i
|
||||
}
|
||||
}
|
||||
return s[left: left+maxLen+1]
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 相关题目推荐
|
||||
|
||||
* 26.删除排序数组中的重复项
|
||||
@ -154,10 +154,6 @@ public:
|
||||
* 844.比较含退格的字符串
|
||||
* 977.有序数组的平方
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
@ -177,6 +173,26 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
```java
|
||||
//相向双指针法
|
||||
class Solution {
|
||||
public int removeElement(int[] nums, int val) {
|
||||
int left = 0;
|
||||
int right = nums.length - 1;
|
||||
while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
|
||||
while(left <= right) {
|
||||
if(nums[left] == val) { //left位置的元素需要移除
|
||||
//将right位置的元素移到left(覆盖),right位置移除
|
||||
nums[left] = nums[right];
|
||||
right--;
|
||||
}
|
||||
left++;
|
||||
while(right >= 0 && nums[right] == val) right--;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
||||
|
@ -226,7 +226,32 @@ class Solution {
|
||||
}
|
||||
}
|
||||
```
|
||||
```java
|
||||
//第二种二分法:左闭右开
|
||||
public int searchInsert(int[] nums, int target) {
|
||||
int left = 0;
|
||||
int right = nums.length;
|
||||
while (left < right) { //左闭右开 [left, right)
|
||||
int middle = left + ((right - left) >> 1);
|
||||
if (nums[middle] > target) {
|
||||
right = middle; // target 在左区间,在[left, middle)中
|
||||
} else if (nums[middle] < target) {
|
||||
left = middle + 1; // target 在右区间,在 [middle+1, right)中
|
||||
} else { // nums[middle] == target
|
||||
return middle; // 数组中找到目标值的情况,直接返回下标
|
||||
}
|
||||
}
|
||||
// 目标值在数组所有元素之前 [0,0)
|
||||
// 目标值插入数组中的位置 [left, right) ,return right 即可
|
||||
// 目标值在数组所有元素之后的情况 [left, right),因为是右开区间,所以 return right
|
||||
return right;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
Golang:
|
||||
|
||||
```golang
|
||||
// 第一种二分法
|
||||
func searchInsert(nums []int, target int) int {
|
||||
|
@ -222,56 +222,6 @@ public:
|
||||
|
||||
## 其他语言补充
|
||||
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def solveNQueens(self, n: int) -> List[List[str]]:
|
||||
if not n: return []
|
||||
board = [['.'] * n for _ in range(n)]
|
||||
res = []
|
||||
def isVaild(board,row, col):
|
||||
#判断同一列是否冲突
|
||||
for i in range(len(board)):
|
||||
if board[i][col] == 'Q':
|
||||
return False
|
||||
# 判断左上角是否冲突
|
||||
i = row -1
|
||||
j = col -1
|
||||
while i>=0 and j>=0:
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j -= 1
|
||||
# 判断右上角是否冲突
|
||||
i = row - 1
|
||||
j = col + 1
|
||||
while i>=0 and j < len(board):
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j += 1
|
||||
return True
|
||||
|
||||
def backtracking(board, row, n):
|
||||
# 如果走到最后一行,说明已经找到一个解
|
||||
if row == n:
|
||||
temp_res = []
|
||||
for temp in board:
|
||||
temp_str = "".join(temp)
|
||||
temp_res.append(temp_str)
|
||||
res.append(temp_res)
|
||||
for col in range(n):
|
||||
if not isVaild(board, row, col):
|
||||
continue
|
||||
board[row][col] = 'Q'
|
||||
backtracking(board, row+1, n)
|
||||
board[row][col] = '.'
|
||||
backtracking(board, 0, n)
|
||||
return res
|
||||
```
|
||||
|
||||
### Java
|
||||
|
||||
```java
|
||||
@ -341,6 +291,55 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def solveNQueens(self, n: int) -> List[List[str]]:
|
||||
if not n: return []
|
||||
board = [['.'] * n for _ in range(n)]
|
||||
res = []
|
||||
def isVaild(board,row, col):
|
||||
#判断同一列是否冲突
|
||||
for i in range(len(board)):
|
||||
if board[i][col] == 'Q':
|
||||
return False
|
||||
# 判断左上角是否冲突
|
||||
i = row -1
|
||||
j = col -1
|
||||
while i>=0 and j>=0:
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j -= 1
|
||||
# 判断右上角是否冲突
|
||||
i = row - 1
|
||||
j = col + 1
|
||||
while i>=0 and j < len(board):
|
||||
if board[i][j] == 'Q':
|
||||
return False
|
||||
i -= 1
|
||||
j += 1
|
||||
return True
|
||||
|
||||
def backtracking(board, row, n):
|
||||
# 如果走到最后一行,说明已经找到一个解
|
||||
if row == n:
|
||||
temp_res = []
|
||||
for temp in board:
|
||||
temp_str = "".join(temp)
|
||||
temp_res.append(temp_str)
|
||||
res.append(temp_res)
|
||||
for col in range(n):
|
||||
if not isVaild(board, row, col):
|
||||
continue
|
||||
board[row][col] = 'Q'
|
||||
backtracking(board, row+1, n)
|
||||
board[row][col] = '.'
|
||||
backtracking(board, 0, n)
|
||||
return res
|
||||
```
|
||||
|
||||
|
||||
### Go
|
||||
```Go
|
||||
@ -396,6 +395,8 @@ func isValid(n, row, col int, chessboard [][]string) bool {
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Javascript
|
||||
```Javascript
|
||||
var solveNQueens = function(n) {
|
||||
|
@ -120,6 +120,20 @@ Java:
|
||||
return res;
|
||||
}
|
||||
```
|
||||
```Java
|
||||
//因为dp[i]的递推公式只与前一个值有关,所以可以用一个变量代替dp数组,空间复杂度为O(1)
|
||||
class Solution {
|
||||
public int maxSubArray(int[] nums) {
|
||||
int res = nums[0];
|
||||
int pre = nums[0];
|
||||
for(int i = 1; i < nums.length; i++) {
|
||||
pre = Math.max(pre + nums[i], nums[i]);
|
||||
res = Math.max(res, pre);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
```python
|
||||
|
@ -133,5 +133,73 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
### Java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public List<Integer> spiralOrder(int[][] matrix) {
|
||||
//存放数组的数
|
||||
List<Integer> ans = new ArrayList<>();
|
||||
//列数
|
||||
int columns = matrix[0].length;
|
||||
//行数
|
||||
int rows = matrix.length;
|
||||
//遍历起点
|
||||
int start = 0;
|
||||
//循环的次数 行数和列数中的最小值除以二
|
||||
int loop = Math.min(rows,columns) / 2;
|
||||
//未遍历的中间列(行)的列(行)下标
|
||||
int mid = loop;
|
||||
//终止条件
|
||||
int offSet = 1;
|
||||
int i,j;
|
||||
while(loop-- > 0) {
|
||||
//初始化起点
|
||||
i = j = start;
|
||||
|
||||
//从左往右
|
||||
for(; j < columns - offSet; j++)
|
||||
ans.add(matrix[i][j]);
|
||||
|
||||
//从上往下
|
||||
for(; i < rows - offSet; i++)
|
||||
ans.add(matrix[i][j]);
|
||||
|
||||
//从右往左
|
||||
for(; j > start; j--)
|
||||
ans.add(matrix[i][j]);
|
||||
|
||||
//从下往上
|
||||
for(; i > start; i--)
|
||||
ans.add(matrix[i][j]);
|
||||
|
||||
//每循环一次 改变起点位置
|
||||
start++;
|
||||
//终止条件改变
|
||||
offSet++;
|
||||
}
|
||||
|
||||
//如果行和列中的最小值是奇数 则会产生中间行或者中间列没有遍历
|
||||
if(Math.min(rows,columns) % 2 != 0) {
|
||||
//行大于列则产生中间列
|
||||
if(rows > columns) {
|
||||
//中间列的行的最大下标的下一位的下标为mid + rows - columns + 1
|
||||
for(int k = mid; k < mid + rows - columns + 1; k++) {
|
||||
ans.add(matrix[k][mid]);
|
||||
}
|
||||
}else {//列大于等于行则产生中间行
|
||||
//中间行的列的最大下标的下一位的下标为mid + columns - rows + 1
|
||||
for(int k = mid; k < mid + columns - rows + 1; k++) {
|
||||
ans.add(matrix[mid][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||
|
@ -187,12 +187,14 @@ func climbStairs(n int) int {
|
||||
JavaScript:
|
||||
```javascript
|
||||
var climbStairs = function(n) {
|
||||
const dp = new Array(n+1).fill(0);
|
||||
const weight = [1,2];
|
||||
const dp = new Array(n + 1).fill(0);
|
||||
const m = 2;
|
||||
dp[0] = 1;
|
||||
for(let i = 0; i <= n; i++){ //先遍历背包
|
||||
for(let j = 0; j < weight.length; j++){ // 再遍历物品
|
||||
if(i >= weight[j]) dp[i] += dp[i-weight[j]];
|
||||
for(let i = 1; i <= n; i++){
|
||||
for(let j = 1; j <= m; j++){
|
||||
if(i >= j) {
|
||||
dp[i] += dp[i - j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[n];
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
大家先回忆一下[77. 组合]给出的回溯法的代码:
|
||||
|
||||
```c++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result; // 存放符合条件结果的集合
|
||||
@ -52,7 +52,7 @@ public:
|
||||
|
||||
在遍历的过程中有如下代码:
|
||||
|
||||
```c++
|
||||
```CPP
|
||||
for (int i = startIndex; i <= n; i++) {
|
||||
path.push_back(i);
|
||||
backtracking(n, k, i + 1);
|
||||
@ -76,7 +76,7 @@ for (int i = startIndex; i <= n; i++) {
|
||||
**如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了**。
|
||||
|
||||
注意代码中i,就是for循环里选择的起始位置。
|
||||
```c++
|
||||
```CPP
|
||||
for (int i = startIndex; i <= n; i++) {
|
||||
```
|
||||
|
||||
@ -98,13 +98,13 @@ for (int i = startIndex; i <= n; i++) {
|
||||
|
||||
所以优化之后的for循环是:
|
||||
|
||||
```c++
|
||||
```CPP
|
||||
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置
|
||||
```
|
||||
|
||||
优化后整体代码如下:
|
||||
|
||||
```c++
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<int>> result;
|
||||
|
@ -237,6 +237,26 @@ class Solution:
|
||||
return True
|
||||
```
|
||||
Go:
|
||||
> 递归法
|
||||
```go
|
||||
func isSameTree(p *TreeNode, q *TreeNode) bool {
|
||||
if p != nil && q == nil {
|
||||
return false
|
||||
}
|
||||
if p == nil && q != nil {
|
||||
return false
|
||||
}
|
||||
if p == nil && q == nil {
|
||||
return true
|
||||
}
|
||||
if p.Val != q.Val {
|
||||
return false
|
||||
}
|
||||
Left := isSameTree(p.Left, q.Left)
|
||||
Right := isSameTree(p.Right, q.Right)
|
||||
return Left && Right
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript:
|
||||
|
||||
@ -253,6 +273,28 @@ var isSameTree = function (p, q) {
|
||||
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
|
||||
};
|
||||
```
|
||||
> 迭代法
|
||||
|
||||
```javascript
|
||||
var isSameTree = (p, q) => {
|
||||
const queue = [{ p, q }];
|
||||
// 这是用{ } 解决了null的问题!
|
||||
while (queue.length) {
|
||||
const cur = queue.shift();
|
||||
if (cur.p == null && cur.q == null) continue;
|
||||
if (cur.p == null || cur.q == null) return false;
|
||||
if (cur.p.val != cur.q.val) return false;
|
||||
queue.push({
|
||||
p: cur.p.left,
|
||||
q: cur.q.left
|
||||
}, {
|
||||
p: cur.p.right,
|
||||
q: cur.q.right
|
||||
});
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
|
@ -813,33 +813,30 @@ go:
|
||||
199. 二叉树的右视图
|
||||
*/
|
||||
func rightSideView(root *TreeNode) []int {
|
||||
queue:=list.New()
|
||||
res:=[][]int{}
|
||||
var finaRes []int
|
||||
if root==nil{
|
||||
return finaRes
|
||||
if root == nil {
|
||||
return nil
|
||||
}
|
||||
res := make([]int, 0)
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
for queue.Len()>0{
|
||||
length:=queue.Len()
|
||||
tmp:=[]int{}
|
||||
for i:=0;i<length;i++{
|
||||
node:=queue.Remove(queue.Front()).(*TreeNode)
|
||||
if node.Left!=nil{
|
||||
|
||||
for queue.Len() > 0 {
|
||||
length := queue.Len()
|
||||
for i := 0; i < length; i++ {
|
||||
node := queue.Remove(queue.Front()).(*TreeNode)
|
||||
if node.Left != nil {
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
if node.Right!=nil{
|
||||
if node.Right != nil {
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
tmp=append(tmp,node.Val)
|
||||
// 取每层的最后一个元素,添加到结果集中
|
||||
if i == length-1 {
|
||||
res = append(res, node.Val)
|
||||
}
|
||||
}
|
||||
res=append(res,tmp)
|
||||
}
|
||||
//取每一层的最后一个元素
|
||||
for i:=0;i<len(res);i++{
|
||||
finaRes=append(finaRes,res[i][len(res[i])-1])
|
||||
}
|
||||
return finaRes
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
@ -1057,40 +1054,34 @@ go:
|
||||
637. 二叉树的层平均值
|
||||
*/
|
||||
func averageOfLevels(root *TreeNode) []float64 {
|
||||
res:=[][]int{}
|
||||
var finRes []float64
|
||||
if root==nil{//防止为空
|
||||
return finRes
|
||||
if root == nil {
|
||||
// 防止为空
|
||||
return nil
|
||||
}
|
||||
queue:=list.New()
|
||||
res := make([]float64, 0)
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
var tmpArr []int
|
||||
for queue.Len()>0 {
|
||||
length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i:=0;i<length;i++{
|
||||
node:=queue.Remove(queue.Front()).(*TreeNode)//出队列
|
||||
if node.Left!=nil{
|
||||
|
||||
var sum int
|
||||
for queue.Len() > 0 {
|
||||
//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
length := queue.Len()
|
||||
for i := 0; i < length; i++ {
|
||||
node := queue.Remove(queue.Front()).(*TreeNode)
|
||||
if node.Left != nil {
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
if node.Right!=nil{
|
||||
if node.Right != nil {
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
tmpArr=append(tmpArr,node.Val)//将值加入本层切片中
|
||||
// 当前层元素求和
|
||||
sum += node.Val
|
||||
}
|
||||
res=append(res,tmpArr)//放入结果集
|
||||
tmpArr=[]int{}//清空层的数据
|
||||
// 计算每层的平均值,将结果添加到响应结果中
|
||||
res = append(res, float64(sum)/float64(length))
|
||||
sum = 0 // 清空该层的数据
|
||||
}
|
||||
//计算每层的平均值
|
||||
length:=len(res)
|
||||
for i:=0;i<length;i++{
|
||||
var sum int
|
||||
for j:=0;j<len(res[i]);j++{
|
||||
sum+=res[i][j]
|
||||
}
|
||||
tmp:=float64(sum)/float64(len(res[i]))
|
||||
finRes=append(finRes,tmp)//将平均值放入结果集合
|
||||
}
|
||||
return finRes
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
@ -1555,44 +1546,40 @@ go:
|
||||
515. 在每个树行中找最大值
|
||||
*/
|
||||
func largestValues(root *TreeNode) []int {
|
||||
res:=[][]int{}
|
||||
var finRes []int
|
||||
if root==nil{//防止为空
|
||||
return finRes
|
||||
if root == nil {
|
||||
//防止为空
|
||||
return nil
|
||||
}
|
||||
queue:=list.New()
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
var tmpArr []int
|
||||
//层次遍历
|
||||
for queue.Len()>0 {
|
||||
length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i:=0;i<length;i++{
|
||||
node:=queue.Remove(queue.Front()).(*TreeNode)//出队列
|
||||
if node.Left!=nil{
|
||||
ans := make([]int, 0)
|
||||
temp := math.MinInt64
|
||||
// 层序遍历
|
||||
for queue.Len() > 0 {
|
||||
//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
length := queue.Len()
|
||||
for i := 0; i < length; i++ {
|
||||
node := queue.Remove(queue.Front()).(*TreeNode)//出队列
|
||||
// 比较当前层中的最大值和新遍历的元素大小,取两者中大值
|
||||
temp = max(temp, node.Val)
|
||||
if node.Left != nil {
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
if node.Right!=nil{
|
||||
if node.Right != nil {
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
tmpArr=append(tmpArr,node.Val)//将值加入本层切片中
|
||||
}
|
||||
res=append(res,tmpArr)//放入结果集
|
||||
tmpArr=[]int{}//清空层的数据
|
||||
ans = append(ans, temp)
|
||||
temp = math.MinInt64
|
||||
}
|
||||
//找到每层的最大值
|
||||
for i:=0;i<len(res);i++{
|
||||
finRes=append(finRes,max(res[i]...))
|
||||
}
|
||||
return finRes
|
||||
return ans
|
||||
}
|
||||
func max(vals...int) int {
|
||||
max:=int(math.Inf(-1))//负无穷
|
||||
for _, val := range vals {
|
||||
if val > max {
|
||||
max = val
|
||||
}
|
||||
|
||||
func max(x, y int) int {
|
||||
if x > y {
|
||||
return x
|
||||
}
|
||||
return max
|
||||
return y
|
||||
}
|
||||
```
|
||||
|
||||
@ -1894,36 +1881,35 @@ go:
|
||||
*/
|
||||
|
||||
func connect(root *Node) *Node {
|
||||
res:=[][]*Node{}
|
||||
if root==nil{//防止为空
|
||||
if root == nil { //防止为空
|
||||
return root
|
||||
}
|
||||
queue:=list.New()
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
var tmpArr []*Node
|
||||
for queue.Len()>0 {
|
||||
length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i:=0;i<length;i++{
|
||||
node:=queue.Remove(queue.Front()).(*Node)//出队列
|
||||
if node.Left!=nil{
|
||||
tmpArr := make([]*Node, 0)
|
||||
for queue.Len() > 0 {
|
||||
length := queue.Len() //保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i := 0; i < length; i++ {
|
||||
node := queue.Remove(queue.Front()).(*Node) //出队列
|
||||
if node.Left != nil {
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
if node.Right!=nil{
|
||||
if node.Right != nil {
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
tmpArr=append(tmpArr,node)//将值加入本层切片中
|
||||
tmpArr = append(tmpArr, node) //将值加入本层切片中
|
||||
}
|
||||
res=append(res,tmpArr)//放入结果集
|
||||
tmpArr=[]*Node{}//清空层的数据
|
||||
}
|
||||
//遍历每层元素,指定next
|
||||
for i:=0;i<len(res);i++{
|
||||
for j:=0;j<len(res[i])-1;j++{
|
||||
res[i][j].Next=res[i][j+1]
|
||||
if len(tmpArr) > 1 {
|
||||
// 遍历每层元素,指定next
|
||||
for i := 0; i < len(tmpArr)-1; i++ {
|
||||
tmpArr[i].Next = tmpArr[i+1]
|
||||
}
|
||||
}
|
||||
tmpArr = []*Node{} //清空层的数据
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Swift:
|
||||
@ -2175,33 +2161,31 @@ go:
|
||||
*/
|
||||
|
||||
func connect(root *Node) *Node {
|
||||
res:=[][]*Node{}
|
||||
if root==nil{//防止为空
|
||||
if root == nil { //防止为空
|
||||
return root
|
||||
}
|
||||
queue:=list.New()
|
||||
queue := list.New()
|
||||
queue.PushBack(root)
|
||||
var tmpArr []*Node
|
||||
for queue.Len()>0 {
|
||||
length:=queue.Len()//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i:=0;i<length;i++{
|
||||
node:=queue.Remove(queue.Front()).(*Node)//出队列
|
||||
if node.Left!=nil{
|
||||
tmpArr := make([]*Node, 0)
|
||||
for queue.Len() > 0 {
|
||||
length := queue.Len() //保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
|
||||
for i := 0; i < length; i++ {
|
||||
node := queue.Remove(queue.Front()).(*Node) //出队列
|
||||
if node.Left != nil {
|
||||
queue.PushBack(node.Left)
|
||||
}
|
||||
if node.Right!=nil{
|
||||
if node.Right != nil {
|
||||
queue.PushBack(node.Right)
|
||||
}
|
||||
tmpArr=append(tmpArr,node)//将值加入本层切片中
|
||||
tmpArr = append(tmpArr, node) //将值加入本层切片中
|
||||
}
|
||||
res=append(res,tmpArr)//放入结果集
|
||||
tmpArr=[]*Node{}//清空层的数据
|
||||
}
|
||||
//遍历每层元素,指定next
|
||||
for i:=0;i<len(res);i++{
|
||||
for j:=0;j<len(res[i])-1;j++{
|
||||
res[i][j].Next=res[i][j+1]
|
||||
if len(tmpArr) > 1 {
|
||||
// 遍历每层元素,指定next
|
||||
for i := 0; i < len(tmpArr)-1; i++ {
|
||||
tmpArr[i].Next = tmpArr[i+1]
|
||||
}
|
||||
}
|
||||
tmpArr = []*Node{} //清空层的数据
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
@ -159,6 +159,57 @@ class Solution:
|
||||
return 0
|
||||
```
|
||||
## Go
|
||||
```go
|
||||
func ladderLength(beginWord string, endWord string, wordList []string) int {
|
||||
wordMap, que, depth := getWordMap(wordList, beginWord), []string{beginWord}, 0
|
||||
for len(que) > 0 {
|
||||
depth++
|
||||
qLen := len(que) // 单词的长度
|
||||
for i := 0; i < qLen; i++ {
|
||||
word := que[0]
|
||||
que = que[1:] // 首位单词出队
|
||||
candidates := getCandidates(word)
|
||||
for _, candidate := range candidates {
|
||||
if _, exist := wordMap[candidate]; exist { // 用生成的结果集去查询
|
||||
if candidate == endWord {
|
||||
return depth + 1
|
||||
}
|
||||
delete(wordMap, candidate) // 删除集合中的用过的结果
|
||||
que = append(que, candidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
// 获取单词Map为后续的查询增加速度
|
||||
func getWordMap(wordList []string, beginWord string) map[string]int {
|
||||
wordMap := make(map[string]int)
|
||||
for i, word := range wordList {
|
||||
if _, exist := wordMap[word]; !exist {
|
||||
if word != beginWord {
|
||||
wordMap[word] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
return wordMap
|
||||
}
|
||||
|
||||
// 用26个英文字母分别替换掉各个位置的字母,生成一个结果集
|
||||
func getCandidates(word string) []string {
|
||||
var res []string
|
||||
for i := 0; i < 26; i++ {
|
||||
for j := 0; j < len(word); j++ {
|
||||
if word[j] != byte(int('a')+i) {
|
||||
res = append(res, word[:j]+string(int('a')+i)+word[j+1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
```
|
||||
|
||||
## JavaScript
|
||||
```javascript
|
||||
|
@ -250,22 +250,22 @@ Go:
|
||||
|
||||
```go
|
||||
func sumNumbers(root *TreeNode) int {
|
||||
sum = 0
|
||||
travel(root, root.Val)
|
||||
return sum
|
||||
sum := 0
|
||||
dfs(root, root.Val, &sum)
|
||||
return sum
|
||||
}
|
||||
|
||||
func travel(root *TreeNode, tmpSum int) {
|
||||
if root.Left == nil && root.Right == nil {
|
||||
sum += tmpSum
|
||||
} else {
|
||||
if root.Left != nil {
|
||||
travel(root.Left, tmpSum*10+root.Left.Val)
|
||||
}
|
||||
if root.Right != nil {
|
||||
travel(root.Right, tmpSum*10+root.Right.Val)
|
||||
}
|
||||
}
|
||||
func dfs(root *TreeNode, tmpSum int, sum *int) {
|
||||
if root.Left == nil && root.Right == nil {
|
||||
*sum += tmpSum
|
||||
} else {
|
||||
if root.Left != nil {
|
||||
dfs(root.Left, tmpSum*10 + root.Left.Val, sum)
|
||||
}
|
||||
if root.Right != nil {
|
||||
dfs(root.Right, tmpSum*10 + root.Right.Val, sum)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -206,6 +206,65 @@ public:
|
||||
return result;
|
||||
}
|
||||
};
|
||||
```
|
||||
# 优化
|
||||
|
||||
上面的代码还存在一定的优化空间, 在于如何更高效的计算一个子字符串是否是回文字串。上述代码```isPalindrome```函数运用双指针的方法来判定对于一个字符串```s```, 给定起始下标和终止下标, 截取出的子字符串是否是回文字串。但是其中有一定的重复计算存在:
|
||||
|
||||
例如给定字符串```"abcde"```, 在已知```"bcd"```不是回文字串时, 不再需要去双指针操作```"abcde"```而可以直接判定它一定不是回文字串。
|
||||
|
||||
具体来说, 给定一个字符串`s`, 长度为```n```, 它成为回文字串的充分必要条件是```s[0] == s[n-1]```且```s[1:n-1]```是回文字串。
|
||||
|
||||
大家如果熟悉动态规划这种算法的话, 我们可以高效地事先一次性计算出, 针对一个字符串```s```, 它的任何子串是否是回文字串, 然后在我们的回溯函数中直接查询即可, 省去了双指针移动判定这一步骤.
|
||||
|
||||
具体参考代码如下:
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
private:
|
||||
vector<vector<string>> result;
|
||||
vector<string> path; // 放已经回文的子串
|
||||
vector<vector<bool>> isPalindrome; // 放事先计算好的是否回文子串的结果
|
||||
void backtracking (const string& s, int startIndex) {
|
||||
// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
|
||||
if (startIndex >= s.size()) {
|
||||
result.push_back(path);
|
||||
return;
|
||||
}
|
||||
for (int i = startIndex; i < s.size(); i++) {
|
||||
if (isPalindrome[startIndex][i]) { // 是回文子串
|
||||
// 获取[startIndex,i]在s中的子串
|
||||
string str = s.substr(startIndex, i - startIndex + 1);
|
||||
path.push_back(str);
|
||||
} else { // 不是回文,跳过
|
||||
continue;
|
||||
}
|
||||
backtracking(s, i + 1); // 寻找i+1为起始位置的子串
|
||||
path.pop_back(); // 回溯过程,弹出本次已经填在的子串
|
||||
}
|
||||
}
|
||||
void computePalindrome(const string& s) {
|
||||
// isPalindrome[i][j] 代表 s[i:j](双边包括)是否是回文字串
|
||||
isPalindrome.resize(s.size(), vector<bool>(s.size(), false)); // 根据字符串s, 刷新布尔矩阵的大小
|
||||
for (int i = s.size() - 1; i >= 0; i--) {
|
||||
// 需要倒序计算, 保证在i行时, i+1行已经计算好了
|
||||
for (int j = i; j < s.size(); j++) {
|
||||
if (j == i) {isPalindrome[i][j] = true;}
|
||||
else if (j - i == 1) {isPalindrome[i][j] = (s[i] == s[j]);}
|
||||
else {isPalindrome[i][j] = (s[i] == s[j] && isPalindrome[i+1][j-1]);}
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
vector<vector<string>> partition(string s) {
|
||||
result.clear();
|
||||
path.clear();
|
||||
computePalindrome(s);
|
||||
backtracking(s, 0);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
# 总结
|
||||
|
@ -137,3 +137,35 @@ public:
|
||||
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
### Java
|
||||
|
||||
下面的代码使用的是深度优先搜索 DFS 的做法。为了统计岛屿数量同时不重复记录,每当我们搜索到一个岛后,就将这个岛 “淹没” —— 将这个岛所占的地方从 “1” 改为 “0”,这样就不用担心后续会重复记录这个岛屿了。而 DFS 的过程就体现在 “淹没” 这一步中。详见代码:
|
||||
|
||||
```java
|
||||
public int numIslands(char[][] grid) {
|
||||
int res = 0; //记录找到的岛屿数量
|
||||
for(int i = 0;i < grid.length;i++){
|
||||
for(int j = 0;j < grid[0].length;j++){
|
||||
//找到“1”,res加一,同时淹没这个岛
|
||||
if(grid[i][j] == '1'){
|
||||
res++;
|
||||
dfs(grid,i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
//使用DFS“淹没”岛屿
|
||||
public void dfs(char[][] grid, int i, int j){
|
||||
//搜索边界:索引越界或遍历到了"0"
|
||||
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == '0') return;
|
||||
//将这块土地标记为"0"
|
||||
grid[i][j] = '0';
|
||||
//根据"每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成",对上下左右的相邻顶点进行dfs
|
||||
dfs(grid,i - 1,j);
|
||||
dfs(grid,i + 1,j);
|
||||
dfs(grid,i,j + 1);
|
||||
dfs(grid,i,j - 1);
|
||||
}
|
||||
```
|
@ -92,18 +92,24 @@ public:
|
||||
|
||||
Java:
|
||||
```java
|
||||
/**
|
||||
* 242. 有效的字母异位词 字典解法
|
||||
* 时间复杂度O(m+n) 空间复杂度O(1)
|
||||
*/
|
||||
class Solution {
|
||||
public boolean isAnagram(String s, String t) {
|
||||
|
||||
int[] record = new int[26];
|
||||
for (char c : s.toCharArray()) {
|
||||
record[c - 'a'] += 1;
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
record[s.charAt(i) - 'a']++;
|
||||
}
|
||||
for (char c : t.toCharArray()) {
|
||||
record[c - 'a'] -= 1;
|
||||
|
||||
for (int i = 0; i < t.length(); i++) {
|
||||
record[t.charAt(i) - 'a']--;
|
||||
}
|
||||
for (int i : record) {
|
||||
if (i != 0) {
|
||||
|
||||
for (int count: record) {
|
||||
if (count != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -261,6 +261,43 @@ for (pair<string, int>target : targets[result[result.size() - 1]])
|
||||
## 其他语言版本
|
||||
|
||||
### java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
private LinkedList<String> res;
|
||||
private LinkedList<String> path = new LinkedList<>();
|
||||
|
||||
public List<String> findItinerary(List<List<String>> tickets) {
|
||||
Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
|
||||
path.add("JFK");
|
||||
boolean[] used = new boolean[tickets.size()];
|
||||
backTracking((ArrayList) tickets, used);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean backTracking(ArrayList<List<String>> tickets, boolean[] used) {
|
||||
if (path.size() == tickets.size() + 1) {
|
||||
res = new LinkedList(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < tickets.size(); i++) {
|
||||
if (!used[i] && tickets.get(i).get(0).equals(path.getLast())) {
|
||||
path.add(tickets.get(i).get(1));
|
||||
used[i] = true;
|
||||
|
||||
if (backTracking(tickets, used)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
used[i] = false;
|
||||
path.removeLast();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
|
@ -134,24 +134,55 @@ public:
|
||||
Java:
|
||||
```java
|
||||
|
||||
/*Comparator接口说明:
|
||||
* 返回负数,形参中第一个参数排在前面;返回正数,形参中第二个参数排在前面
|
||||
* 对于队列:排在前面意味着往队头靠
|
||||
* 对于堆(使用PriorityQueue实现):从队头到队尾按从小到大排就是最小堆(小顶堆),
|
||||
* 从队头到队尾按从大到小排就是最大堆(大顶堆)--->队头元素相当于堆的根节点
|
||||
* */
|
||||
class Solution {
|
||||
public int[] topKFrequent(int[] nums, int k) {
|
||||
int[] result = new int[k];
|
||||
HashMap<Integer, Integer> map = new HashMap<>();
|
||||
for (int num : nums) {
|
||||
map.put(num, map.getOrDefault(num, 0) + 1);
|
||||
//解法1:基于大顶堆实现
|
||||
public int[] topKFrequent1(int[] nums, int k) {
|
||||
Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数
|
||||
for(int num:nums){
|
||||
map.put(num,map.getOrDefault(num,0)+1);
|
||||
}
|
||||
|
||||
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
|
||||
// 根据map的value值,构建于一个大顶堆(o1 - o2: 小顶堆, o2 - o1 : 大顶堆)
|
||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o2.getValue() - o1.getValue());
|
||||
for (Map.Entry<Integer, Integer> entry : entries) {
|
||||
queue.offer(entry);
|
||||
//在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
|
||||
//出现次数按从队头到队尾的顺序是从大到小排,出现次数最多的在队头(相当于大顶堆)
|
||||
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2)->pair2[1]-pair1[1]);
|
||||
for(Map.Entry<Integer,Integer> entry:map.entrySet()){//大顶堆需要对所有元素进行排序
|
||||
pq.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
}
|
||||
for (int i = k - 1; i >= 0; i--) {
|
||||
result[i] = queue.poll().getKey();
|
||||
int[] ans = new int[k];
|
||||
for(int i=0;i<k;i++){//依次从队头弹出k个,就是出现频率前k高的元素
|
||||
ans[i] = pq.poll()[0];
|
||||
}
|
||||
return result;
|
||||
return ans;
|
||||
}
|
||||
//解法2:基于小顶堆实现
|
||||
public int[] topKFrequent2(int[] nums, int k) {
|
||||
Map<Integer,Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数
|
||||
for(int num:nums){
|
||||
map.put(num,map.getOrDefault(num,0)+1);
|
||||
}
|
||||
//在优先队列中存储二元组(num,cnt),cnt表示元素值num在数组中的出现次数
|
||||
//出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(相当于小顶堆)
|
||||
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2)->pair1[1]-pair2[1]);
|
||||
for(Map.Entry<Integer,Integer> entry:map.entrySet()){//小顶堆只需要维持k个元素有序
|
||||
if(pq.size()<k){//小顶堆元素个数小于k个时直接加
|
||||
pq.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
}else{
|
||||
if(entry.getValue()>pq.peek()[1]){//当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)
|
||||
pq.poll();//弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了
|
||||
pq.add(new int[]{entry.getKey(),entry.getValue()});
|
||||
}
|
||||
}
|
||||
}
|
||||
int[] ans = new int[k];
|
||||
for(int i=k-1;i>=0;i--){//依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多
|
||||
ans[i] = pq.poll()[0];
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -262,99 +293,102 @@ func topKFrequent(nums []int, k int) []int {
|
||||
|
||||
|
||||
|
||||
javaScript:
|
||||
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();
|
||||
// js 没有堆 需要自己构造
|
||||
class Heap {
|
||||
constructor(compareFn) {
|
||||
this.compareFn = compareFn;
|
||||
this.queue = [];
|
||||
}
|
||||
}
|
||||
|
||||
const ret = [];
|
||||
// 添加
|
||||
push(item) {
|
||||
// 推入元素
|
||||
this.queue.push(item);
|
||||
|
||||
for(let i = priorityQueue.size() - 1; i >= 0; i--) {
|
||||
ret[i] = priorityQueue.pop()[0];
|
||||
}
|
||||
// 上浮
|
||||
let index = this.size() - 1; // 记录推入元素下标
|
||||
let parent = Math.floor((index - 1) / 2); // 记录父节点下标
|
||||
|
||||
return ret;
|
||||
while (parent >= 0 && this.compare(parent, index) > 0) { // 注意compare参数顺序
|
||||
[this.queue[index], this.queue[parent]] = [this.queue[parent], this.queue[index]];
|
||||
|
||||
// 更新下标
|
||||
index = parent;
|
||||
parent = Math.floor((index - 1) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取堆顶元素并移除
|
||||
pop() {
|
||||
// 堆顶元素
|
||||
const out = this.queue[0];
|
||||
|
||||
// 移除堆顶元素 填入最后一个元素
|
||||
this.queue[0] = this.queue.pop();
|
||||
|
||||
// 下沉
|
||||
let index = 0; // 记录下沉元素下标
|
||||
let left = 1; // left 是左子节点下标 left + 1 则是右子节点下标
|
||||
let searchChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
|
||||
|
||||
while (searchChild !== undefined && this.compare(index, searchChild) > 0) { // 注意compare参数顺序
|
||||
[this.queue[index], this.queue[searchChild]] = [this.queue[searchChild], this.queue[index]];
|
||||
|
||||
// 更新下标
|
||||
index = searchChild;
|
||||
left = 2 * index + 1;
|
||||
searchChild = this.compare(left, left + 1) > 0 ? left + 1 : left;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.queue.length;
|
||||
}
|
||||
|
||||
// 使用传入的 compareFn 比较两个位置的元素
|
||||
compare(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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const topKFrequent = function (nums, k) {
|
||||
const map = new Map();
|
||||
|
||||
for (const num of nums) {
|
||||
map.set(num, (map.get(num) || 0) + 1);
|
||||
}
|
||||
|
||||
// 创建小顶堆
|
||||
const heap= new Heap((a, b) => a[1] - b[1]);
|
||||
|
||||
// entry 是一个长度为2的数组,0位置存储key,1位置存储value
|
||||
for (const entry of map.entries()) {
|
||||
heap.push(entry);
|
||||
|
||||
if (heap.size() > k) {
|
||||
heap.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// return heap.queue.map(e => e[0]);
|
||||
|
||||
const res = [];
|
||||
|
||||
for (let i = heap.size() - 1; i >= 0; i--) {
|
||||
res[i] = heap.pop()[0];
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
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]);
|
||||
}
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
@ -152,6 +152,8 @@ public:
|
||||
for (int i = 0; i < nums.size(); i++) {
|
||||
sum += nums[i];
|
||||
}
|
||||
// 也可以使用库函数一步求和
|
||||
// int sum = accumulate(nums.begin(), nums.end(), 0);
|
||||
if (sum % 2 == 1) return false;
|
||||
int target = sum / 2;
|
||||
|
||||
|
@ -118,6 +118,27 @@ class Solution {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// 解法二
|
||||
class Solution {
|
||||
public int islandPerimeter(int[][] grid) {
|
||||
// 计算岛屿的周长
|
||||
// 方法二 : 遇到相邻的陆地总周长就-2
|
||||
int landSum = 0; // 陆地数量
|
||||
int cover = 0; // 相邻陆地数量
|
||||
for (int i = 0; i < grid.length; i++) {
|
||||
for (int j = 0; j < grid[0].length; j++) {
|
||||
if (grid[i][j] == 1) {
|
||||
landSum++;
|
||||
// 统计上面和左边的相邻陆地
|
||||
if(i - 1 >= 0 && grid[i-1][j] == 1) cover++;
|
||||
if(j - 1 >= 0 && grid[i][j-1] == 1) cover++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return landSum * 4 - cover * 2;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Python:
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
[力扣题目链接](https://leetcode.cn/problems/reverse-string-ii/)
|
||||
|
||||
给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。
|
||||
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
|
||||
|
||||
如果剩余字符少于 k 个,则将剩余字符全部反转。
|
||||
|
||||
|
@ -290,10 +290,11 @@ func search(nums []int, target int) int {
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
// right是数组最后一个数的下标,num[right]在查找范围内,是左闭右闭区间
|
||||
let left = 0, right = nums.length - 1;
|
||||
let mid, left = 0, right = nums.length - 1;
|
||||
// 当left=right时,由于nums[right]在查找范围内,所以要包括此情况
|
||||
while (left <= right) {
|
||||
let mid = left + Math.floor((right - left)/2);
|
||||
// 位运算 + 防止大数溢出
|
||||
mid = left + ((right - left) >> 1);
|
||||
// 如果中间数大于目标值,要把中间数排除查找范围,所以右边界更新为mid-1;如果右边界更新为mid,那中间数还在下次查找范围内
|
||||
if (nums[mid] > target) {
|
||||
right = mid - 1; // 去左面闭区间寻找
|
||||
@ -316,10 +317,11 @@ var search = function(nums, target) {
|
||||
*/
|
||||
var search = function(nums, target) {
|
||||
// right是数组最后一个数的下标+1,nums[right]不在查找范围内,是左闭右开区间
|
||||
let left = 0, right = nums.length;
|
||||
let mid, left = 0, right = nums.length;
|
||||
// 当left=right时,由于nums[right]不在查找范围,所以不必包括此情况
|
||||
while (left < right) {
|
||||
let mid = left + Math.floor((right - left)/2);
|
||||
// 位运算 + 防止大数溢出
|
||||
mid = left + ((right - left) >> 1);
|
||||
// 如果中间值大于目标值,中间值不应在下次查找的范围内,但中间值的前一个值应在;
|
||||
// 由于right本来就不在查找范围内,所以将右边界更新为中间值,如果更新右边界为mid-1则将中间值的前一个值也踢出了下次寻找范围
|
||||
if (nums[mid] > target) {
|
||||
@ -340,9 +342,10 @@ var search = function(nums, target) {
|
||||
|
||||
```typescript
|
||||
function search(nums: number[], target: number): number {
|
||||
let left: number = 0, right: number = nums.length - 1;
|
||||
let mid: number, left: number = 0, right: number = nums.length - 1;
|
||||
while (left <= right) {
|
||||
let mid: number = left + Math.floor((right - left) / 2);
|
||||
// 位运算 + 防止大数溢出
|
||||
mid = left + ((right - left) >> 1);
|
||||
if (nums[mid] > target) {
|
||||
right = mid - 1;
|
||||
} else if (nums[mid] < target) {
|
||||
@ -359,9 +362,10 @@ function search(nums: number[], target: number): number {
|
||||
|
||||
```typescript
|
||||
function search(nums: number[], target: number): number {
|
||||
let left: number = 0, right: number = nums.length;
|
||||
let mid: number, left: number = 0, right: number = nums.length;
|
||||
while (left < right) {
|
||||
let mid: number = left + Math.floor((right - left) / 2);
|
||||
// 位运算 + 防止大数溢出
|
||||
mid = left +((right - left) >> 1);
|
||||
if (nums[mid] > target) {
|
||||
right = mid;
|
||||
} else if (nums[mid] < target) {
|
||||
|
@ -353,8 +353,12 @@ class MyLinkedList {
|
||||
return;
|
||||
}
|
||||
size--;
|
||||
if (index == 0) {
|
||||
head = head.next;
|
||||
return;
|
||||
}
|
||||
ListNode pred = head;
|
||||
for (int i = 0; i < index; i++) {
|
||||
for (int i = 0; i < index - 1; i++) {
|
||||
pred = pred.next;
|
||||
}
|
||||
pred.next = pred.next.next;
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
### Java:
|
||||
### Java
|
||||
|
||||
```java
|
||||
// 普通方法(使用栈的思路)
|
||||
@ -214,7 +214,80 @@ public static boolean backspaceCompare(String s, String t) {
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public static boolean backspaceCompare(String s, String t) {
|
||||
return getStr(s).equals(getStr(t));
|
||||
}
|
||||
|
||||
public static String getStr(String s) { //使用快慢双指针去除字符串中的#
|
||||
int slowIndex;
|
||||
int fastIndex = 0;
|
||||
StringBuilder builder = new StringBuilder(s); //StringBuilder用于修改字符串
|
||||
for(slowIndex = 0; fastIndex < s.length(); fastIndex++) {
|
||||
if(builder.charAt(fastIndex) != '#') {
|
||||
builder.setCharAt(slowIndex++,builder.charAt(fastIndex));
|
||||
} else {
|
||||
if(slowIndex > 0) {
|
||||
slowIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.toString().substring(0,slowIndex); //截取有效字符串
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
从后往前双指针:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public static boolean backspaceCompare(String s, String t) {
|
||||
int sSkipNum = 0; //记录s的#的个数
|
||||
int tSkipNum = 0; //记录t的#的个数
|
||||
int sIndex = s.length() - 1;
|
||||
int tIndex = t.length() - 1;
|
||||
while(true) {
|
||||
while(sIndex >= 0) { //每次记录连续的#并跳过被删除的字符
|
||||
if(s.charAt(sIndex) == '#') {
|
||||
sSkipNum++;
|
||||
} else {
|
||||
if(sSkipNum > 0) {
|
||||
sSkipNum--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sIndex--;
|
||||
}
|
||||
while(tIndex >= 0) { //每次记录连续的#并跳过被删除的字符
|
||||
if(t.charAt(tIndex) == '#') {
|
||||
tSkipNum++;
|
||||
} else {
|
||||
if(tSkipNum > 0) {
|
||||
tSkipNum--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tIndex--;
|
||||
}
|
||||
if(sIndex < 0 || tIndex < 0) { //s 或者 t遍历完了
|
||||
break;
|
||||
}
|
||||
if(s.charAt(sIndex) != t.charAt(tIndex)) { //当前下标的字符不相等
|
||||
return false;
|
||||
}
|
||||
sIndex--;
|
||||
tIndex--;
|
||||
}
|
||||
if(sIndex == -1 && tIndex == -1) { //同时遍历完 则相等
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### python
|
||||
|
||||
|
@ -239,18 +239,24 @@ 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;
|
||||
const ans: number[] = [];
|
||||
let left = 0,
|
||||
right = nums.length - 1;
|
||||
|
||||
while (left <= right) {
|
||||
if (Math.abs(nums[left]) < Math.abs(nums[right])) {
|
||||
resArr[resArrIndex] = nums[right--] ** 2;
|
||||
// 右侧的元素不需要取绝对值,nums 为非递减排序的整数数组
|
||||
// 在同为负数的情况下,左侧的平方值一定大于右侧的平方值
|
||||
if (Math.abs(nums[left]) > nums[right]) {
|
||||
// 使用 Array.prototype.unshift() 直接在数组的首项插入当前最大值
|
||||
ans.unshift(nums[left] ** 2);
|
||||
left++;
|
||||
} else {
|
||||
resArr[resArrIndex] = nums[left++] ** 2;
|
||||
ans.unshift(nums[right] ** 2);
|
||||
right--;
|
||||
}
|
||||
resArrIndex--;
|
||||
}
|
||||
return resArr;
|
||||
|
||||
return ans;
|
||||
};
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user