mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-07 07:35:35 +08:00
Merge branch 'master' into master
This commit is contained in:
@ -1,56 +0,0 @@
|
|||||||
JAVA:
|
|
||||||
|
|
||||||
```Java
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Main{
|
|
||||||
public static void main(String[] args) {
|
|
||||||
int N, M;
|
|
||||||
Scanner scanner = new Scanner(System.in);
|
|
||||||
N = scanner.nextInt();
|
|
||||||
M = scanner.nextInt();
|
|
||||||
DisJoint disJoint = new DisJoint(N + 1);
|
|
||||||
for (int i = 0; i < M; ++i) {
|
|
||||||
disJoint.join(scanner.nextInt(), scanner.nextInt());
|
|
||||||
}
|
|
||||||
if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())) {
|
|
||||||
System.out.println("1");
|
|
||||||
} else {
|
|
||||||
System.out.println("0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//并查集模板
|
|
||||||
class DisJoint{
|
|
||||||
private int[] father;
|
|
||||||
|
|
||||||
public DisJoint(int N) {
|
|
||||||
father = new int[N];
|
|
||||||
for (int i = 0; i < N; ++i){
|
|
||||||
father[i] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int find(int n) {
|
|
||||||
return n == father[n] ? n : (father[n] = find(father[n]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void join (int n, int m) {
|
|
||||||
n = find(n);
|
|
||||||
m = find(m);
|
|
||||||
if (n == m) return;
|
|
||||||
father[m] = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSame(int n, int m){
|
|
||||||
n = find(n);
|
|
||||||
m = find(m);
|
|
||||||
return n == m;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
@ -267,6 +267,7 @@ class Solution {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重
|
if (j > i + 1 && nums[j - 1] == nums[j]) { // 对nums[j]去重
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +371,7 @@ class Solution:
|
|||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
动态规划
|
||||||
```Go
|
```Go
|
||||||
func uniquePaths(m int, n int) int {
|
func uniquePaths(m int, n int) int {
|
||||||
dp := make([][]int, m)
|
dp := make([][]int, m)
|
||||||
@ -390,6 +391,26 @@ func uniquePaths(m int, n int) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
数论方法
|
||||||
|
```Go
|
||||||
|
func uniquePaths(m int, n int) int {
|
||||||
|
numerator := 1
|
||||||
|
denominator := m - 1
|
||||||
|
count := m - 1
|
||||||
|
t := m + n - 2
|
||||||
|
for count > 0 {
|
||||||
|
numerator *= t
|
||||||
|
t--
|
||||||
|
for denominator != 0 && numerator % denominator == 0 {
|
||||||
|
numerator /= denominator
|
||||||
|
denominator--
|
||||||
|
}
|
||||||
|
count--
|
||||||
|
}
|
||||||
|
return numerator
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
||||||
```Javascript
|
```Javascript
|
||||||
|
@ -310,6 +310,43 @@ class Solution:
|
|||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
使用used数组
|
||||||
|
```Go
|
||||||
|
var (
|
||||||
|
result [][]int
|
||||||
|
path []int
|
||||||
|
)
|
||||||
|
|
||||||
|
func subsetsWithDup(nums []int) [][]int {
|
||||||
|
result = make([][]int, 0)
|
||||||
|
path = make([]int, 0)
|
||||||
|
used := make([]bool, len(nums))
|
||||||
|
sort.Ints(nums) // 去重需要排序
|
||||||
|
backtracing(nums, 0, used)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func backtracing(nums []int, startIndex int, used []bool) {
|
||||||
|
tmp := make([]int, len(path))
|
||||||
|
copy(tmp, path)
|
||||||
|
result = append(result, tmp)
|
||||||
|
for i := startIndex; i < len(nums); i++ {
|
||||||
|
// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
|
||||||
|
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
|
||||||
|
// 而我们要对同一树层使用过的元素进行跳过
|
||||||
|
if i > 0 && nums[i] == nums[i-1] && used[i-1] == false {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path = append(path, nums[i])
|
||||||
|
used[i] = true
|
||||||
|
backtracing(nums, i + 1, used)
|
||||||
|
path = path[:len(path)-1]
|
||||||
|
used[i] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
不使用used数组
|
||||||
```Go
|
```Go
|
||||||
var (
|
var (
|
||||||
path []int
|
path []int
|
||||||
|
@ -143,7 +143,7 @@ for (int i = startIndex; i < s.size(); i++) {
|
|||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```CPP
|
```CPP
|
||||||
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
|
// 判断字符串s在左闭右闭区间[start, end]所组成的数字是否合法
|
||||||
bool isValid(const string& s, int start, int end) {
|
bool isValid(const string& s, int start, int end) {
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
return false;
|
return false;
|
||||||
@ -208,7 +208,7 @@ private:
|
|||||||
} else break; // 不合法,直接结束本层循环
|
} else break; // 不合法,直接结束本层循环
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 判断字符串s在左闭又闭区间[start, end]所组成的数字是否合法
|
// 判断字符串s在左闭右闭区间[start, end]所组成的数字是否合法
|
||||||
bool isValid(const string& s, int start, int end) {
|
bool isValid(const string& s, int start, int end) {
|
||||||
if (start > end) {
|
if (start > end) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -623,6 +623,8 @@ class Solution:
|
|||||||
```
|
```
|
||||||
### Go:
|
### Go:
|
||||||
|
|
||||||
|
递归法
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
func isBalanced(root *TreeNode) bool {
|
func isBalanced(root *TreeNode) bool {
|
||||||
h := getHeight(root)
|
h := getHeight(root)
|
||||||
@ -653,6 +655,64 @@ func max(a, b int) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
迭代法
|
||||||
|
|
||||||
|
```Go
|
||||||
|
func isBalanced(root *TreeNode) bool {
|
||||||
|
st := make([]*TreeNode, 0)
|
||||||
|
if root == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
st = append(st, root)
|
||||||
|
for len(st) > 0 {
|
||||||
|
node := st[len(st)-1]
|
||||||
|
st = st[:len(st)-1]
|
||||||
|
if math.Abs(float64(getDepth(node.Left)) - float64(getDepth(node.Right))) > 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if node.Right != nil {
|
||||||
|
st = append(st, node.Right)
|
||||||
|
}
|
||||||
|
if node.Left != nil {
|
||||||
|
st = append(st, node.Left)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDepth(cur *TreeNode) int {
|
||||||
|
st := make([]*TreeNode, 0)
|
||||||
|
if cur != nil {
|
||||||
|
st = append(st, cur)
|
||||||
|
}
|
||||||
|
depth := 0
|
||||||
|
result := 0
|
||||||
|
for len(st) > 0 {
|
||||||
|
node := st[len(st)-1]
|
||||||
|
if node != nil {
|
||||||
|
st = st[:len(st)-1]
|
||||||
|
st = append(st, node, nil)
|
||||||
|
depth++
|
||||||
|
if node.Right != nil {
|
||||||
|
st = append(st, node.Right)
|
||||||
|
}
|
||||||
|
if node.Left != nil {
|
||||||
|
st = append(st, node.Left)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
st = st[:len(st)-1]
|
||||||
|
node = st[len(st)-1]
|
||||||
|
st = st[:len(st)-1]
|
||||||
|
depth--
|
||||||
|
}
|
||||||
|
if result < depth {
|
||||||
|
result = depth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### JavaScript:
|
### JavaScript:
|
||||||
|
|
||||||
递归法:
|
递归法:
|
||||||
|
@ -727,6 +727,48 @@ class Solution:
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
//递归法
|
//递归法
|
||||||
|
/**
|
||||||
|
* Definition for a binary tree node.
|
||||||
|
* type TreeNode struct {
|
||||||
|
* Val int
|
||||||
|
* Left *TreeNode
|
||||||
|
* Right *TreeNode
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
func hasPathSum(root *TreeNode, targetSum int) bool {
|
||||||
|
if root == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return traversal(root, targetSum - root.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traversal(cur *TreeNode, count int) bool {
|
||||||
|
if cur.Left == nil && cur.Right == nil && count == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if cur.Left == nil && cur.Right == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if cur.Left != nil {
|
||||||
|
count -= cur.Left.Val
|
||||||
|
if traversal(cur.Left, count) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
count += cur.Left.Val
|
||||||
|
}
|
||||||
|
if cur.Right != nil {
|
||||||
|
count -= cur.Right.Val
|
||||||
|
if traversal(cur.Right, count) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
count += cur.Right.Val
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
//递归法精简
|
||||||
/**
|
/**
|
||||||
* Definition for a binary tree node.
|
* Definition for a binary tree node.
|
||||||
* type TreeNode struct {
|
* type TreeNode struct {
|
||||||
|
@ -527,6 +527,7 @@ class Solution:
|
|||||||
|
|
||||||
```
|
```
|
||||||
### Go
|
### Go
|
||||||
|
回溯 基本版
|
||||||
```go
|
```go
|
||||||
var (
|
var (
|
||||||
path []string // 放已经回文的子串
|
path []string // 放已经回文的子串
|
||||||
@ -565,6 +566,63 @@ func isPalindrome(s string) bool {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
回溯+动态规划优化回文串判断
|
||||||
|
```go
|
||||||
|
var (
|
||||||
|
result [][]string
|
||||||
|
path []string // 放已经回文的子串
|
||||||
|
isPalindrome [][]bool // 放事先计算好的是否回文子串的结果
|
||||||
|
)
|
||||||
|
|
||||||
|
func partition(s string) [][]string {
|
||||||
|
result = make([][]string, 0)
|
||||||
|
path = make([]string, 0)
|
||||||
|
computePalindrome(s)
|
||||||
|
backtracing(s, 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func backtracing(s string, startIndex int) {
|
||||||
|
// 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
|
||||||
|
if startIndex >= len(s) {
|
||||||
|
tmp := make([]string, len(path))
|
||||||
|
copy(tmp, path)
|
||||||
|
result = append(result, tmp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := startIndex; i < len(s); i++ {
|
||||||
|
if isPalindrome[startIndex][i] { // 是回文子串
|
||||||
|
// 获取[startIndex,i]在s中的子串
|
||||||
|
path = append(path, s[startIndex:i+1])
|
||||||
|
} else { // 不是回文,跳过
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
backtracing(s, i + 1) // 寻找i+1为起始位置的子串
|
||||||
|
path = path[:len(path)-1] // 回溯过程,弹出本次已经添加的子串
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func computePalindrome(s string) {
|
||||||
|
// isPalindrome[i][j] 代表 s[i:j](双边包括)是否是回文字串
|
||||||
|
isPalindrome = make([][]bool, len(s))
|
||||||
|
for i := 0; i < len(isPalindrome); i++ {
|
||||||
|
isPalindrome[i] = make([]bool, len(s))
|
||||||
|
}
|
||||||
|
for i := len(s)-1; i >= 0; i-- {
|
||||||
|
// 需要倒序计算, 保证在i行时, i+1行已经计算好了
|
||||||
|
for j := i; j < len(s); 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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### JavaScript
|
### JavaScript
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -149,7 +149,35 @@ public:
|
|||||||
* 时间复杂度: O(n)
|
* 时间复杂度: O(n)
|
||||||
* 空间复杂度: O(1)
|
* 空间复杂度: O(1)
|
||||||
|
|
||||||
|
**也可以通过递归的思路解决本题:**
|
||||||
|
|
||||||
|
基础情况:对于空链表,不需要移除元素。
|
||||||
|
|
||||||
|
递归情况:首先检查头节点的值是否为 val,如果是则移除头节点,答案即为在头节点的后续节点上递归的结果;如果头节点的值不为 val,则答案为头节点与在头节点的后续节点上递归得到的新链表拼接的结果。
|
||||||
|
|
||||||
|
```CPP
|
||||||
|
class Solution {
|
||||||
|
public:
|
||||||
|
ListNode* removeElements(ListNode* head, int val) {
|
||||||
|
// 基础情况:空链表
|
||||||
|
if (head == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归处理
|
||||||
|
if (head->val == val) {
|
||||||
|
ListNode* newHead = removeElements(head->next, val);
|
||||||
|
delete head;
|
||||||
|
return newHead;
|
||||||
|
} else {
|
||||||
|
head->next = removeElements(head->next, val);
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
* 时间复杂度:O(n)
|
||||||
|
* 空间复杂度:O(n)
|
||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈)
|
这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,全当一个乐子哈)
|
||||||
|
|
||||||
## 算法公开课
|
## 算法公开课
|
||||||
|
|
||||||
@ -1033,3 +1033,4 @@ public TreeNode InvertTree(TreeNode root) {
|
|||||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -337,6 +337,21 @@ func sumOfLeftLeaves(root *TreeNode) int {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**递归精简版**
|
||||||
|
|
||||||
|
```go
|
||||||
|
func sumOfLeftLeaves(root *TreeNode) int {
|
||||||
|
if root == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
leftValue := 0
|
||||||
|
if root.Left != nil && root.Left.Left == nil && root.Left.Right == nil {
|
||||||
|
leftValue = root.Left.Val
|
||||||
|
}
|
||||||
|
return leftValue + sumOfLeftLeaves(root.Left) + sumOfLeftLeaves(root.Right)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
**迭代法(前序遍历)**
|
**迭代法(前序遍历)**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -165,6 +165,140 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
### C++双链表法:
|
||||||
|
|
||||||
|
```CPP
|
||||||
|
//采用循环虚拟结点的双链表实现
|
||||||
|
class MyLinkedList {
|
||||||
|
public:
|
||||||
|
// 定义双向链表节点结构体
|
||||||
|
struct DList {
|
||||||
|
int elem; // 节点存储的元素
|
||||||
|
DList *next; // 指向下一个节点的指针
|
||||||
|
DList *prev; // 指向上一个节点的指针
|
||||||
|
// 构造函数,创建一个值为elem的新节点
|
||||||
|
DList(int elem) : elem(elem), next(nullptr), prev(nullptr) {};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 构造函数,初始化链表
|
||||||
|
MyLinkedList() {
|
||||||
|
sentinelNode = new DList(0); // 创建哨兵节点,不存储有效数据
|
||||||
|
sentinelNode->next = sentinelNode; // 哨兵节点的下一个节点指向自身,形成循环
|
||||||
|
sentinelNode->prev = sentinelNode; // 哨兵节点的上一个节点指向自身,形成循环
|
||||||
|
size = 0; // 初始化链表大小为0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取链表中第index个节点的值
|
||||||
|
int get(int index) {
|
||||||
|
if (index > (size - 1) || index < 0) { // 检查索引是否超出范围
|
||||||
|
return -1; // 如果超出范围,返回-1
|
||||||
|
}
|
||||||
|
int num;
|
||||||
|
int mid = size >> 1; // 计算链表中部位置
|
||||||
|
DList *curNode = sentinelNode; // 从哨兵节点开始
|
||||||
|
if (index < mid) { // 如果索引小于中部位置,从前往后遍历
|
||||||
|
for (int i = 0; i < index + 1; i++) {
|
||||||
|
curNode = curNode->next; // 移动到目标节点
|
||||||
|
}
|
||||||
|
} else { // 如果索引大于等于中部位置,从后往前遍历
|
||||||
|
for (int i = 0; i < size - index; i++) {
|
||||||
|
curNode = curNode->prev; // 移动到目标节点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num = curNode->elem; // 获取目标节点的值
|
||||||
|
return num; // 返回节点的值
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在链表头部添加节点
|
||||||
|
void addAtHead(int val) {
|
||||||
|
DList *newNode = new DList(val); // 创建新节点
|
||||||
|
DList *next = sentinelNode->next; // 获取当前头节点的下一个节点
|
||||||
|
newNode->prev = sentinelNode; // 新节点的上一个节点指向哨兵节点
|
||||||
|
newNode->next = next; // 新节点的下一个节点指向原来的头节点
|
||||||
|
size++; // 链表大小加1
|
||||||
|
sentinelNode->next = newNode; // 哨兵节点的下一个节点指向新节点
|
||||||
|
next->prev = newNode; // 原来的头节点的上一个节点指向新节点
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在链表尾部添加节点
|
||||||
|
void addAtTail(int val) {
|
||||||
|
DList *newNode = new DList(val); // 创建新节点
|
||||||
|
DList *prev = sentinelNode->prev; // 获取当前尾节点的上一个节点
|
||||||
|
newNode->next = sentinelNode; // 新节点的下一个节点指向哨兵节点
|
||||||
|
newNode->prev = prev; // 新节点的上一个节点指向原来的尾节点
|
||||||
|
size++; // 链表大小加1
|
||||||
|
sentinelNode->prev = newNode; // 哨兵节点的上一个节点指向新节点
|
||||||
|
prev->next = newNode; // 原来的尾节点的下一个节点指向新节点
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在链表中的第index个节点之前添加值为val的节点
|
||||||
|
void addAtIndex(int index, int val) {
|
||||||
|
if (index > size) { // 检查索引是否超出范围
|
||||||
|
return; // 如果超出范围,直接返回
|
||||||
|
}
|
||||||
|
if (index <= 0) { // 如果索引为0或负数,在头部添加节点
|
||||||
|
addAtHead(val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int num;
|
||||||
|
int mid = size >> 1; // 计算链表中部位置
|
||||||
|
DList *curNode = sentinelNode; // 从哨兵节点开始
|
||||||
|
if (index < mid) { // 如果索引小于中部位置,从前往后遍历
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
curNode = curNode->next; // 移动到目标位置的前一个节点
|
||||||
|
}
|
||||||
|
DList *temp = curNode->next; // 获取目标位置的节点
|
||||||
|
DList *newNode = new DList(val); // 创建新节点
|
||||||
|
curNode->next = newNode; // 在目标位置前添加新节点
|
||||||
|
temp->prev = newNode; // 目标位置的节点的前一个节点指向新节点
|
||||||
|
newNode->next = temp; // 新节点的下一个节点指向目标位置的结点
|
||||||
|
newNode->prev = curNode; // 新节点的上一个节点指向当前节点
|
||||||
|
} else { // 如果索引大于等于中部位置,从后往前遍历
|
||||||
|
for (int i = 0; i < size - index; i++) {
|
||||||
|
curNode = curNode->prev; // 移动到目标位置的后一个节点
|
||||||
|
}
|
||||||
|
DList *temp = curNode->prev; // 获取目标位置的节点
|
||||||
|
DList *newNode = new DList(val); // 创建新节点
|
||||||
|
curNode->prev = newNode; // 在目标位置后添加新节点
|
||||||
|
temp->next = newNode; // 目标位置的节点的下一个节点指向新节点
|
||||||
|
newNode->prev = temp; // 新节点的上一个节点指向目标位置的节点
|
||||||
|
newNode->next = curNode; // 新节点的下一个节点指向当前节点
|
||||||
|
}
|
||||||
|
size++; // 链表大小加1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除链表中的第index个节点
|
||||||
|
void deleteAtIndex(int index) {
|
||||||
|
if (index > (size - 1) || index < 0) { // 检查索引是否超出范围
|
||||||
|
return; // 如果超出范围,直接返回
|
||||||
|
}
|
||||||
|
int num;
|
||||||
|
int mid = size >> 1; // 计算链表中部位置
|
||||||
|
DList *curNode = sentinelNode; // 从哨兵节点开始
|
||||||
|
if (index < mid) { // 如果索引小于中部位置,从前往后遍历
|
||||||
|
for (int i = 0; i < index; i++) {
|
||||||
|
curNode = curNode->next; // 移动到目标位置的前一个节点
|
||||||
|
}
|
||||||
|
DList *next = curNode->next->next; // 获取目标位置的下一个节点
|
||||||
|
curNode->next = next; // 删除目标位置的节点
|
||||||
|
next->prev = curNode; // 目标位置的下一个节点的前一个节点指向当前节点
|
||||||
|
} else { // 如果索引大于等于中部位置,从后往前遍历
|
||||||
|
for (int i = 0; i < size - index - 1; i++) {
|
||||||
|
curNode = curNode->prev; // 移动到目标位置的后一个节点
|
||||||
|
}
|
||||||
|
DList *prev = curNode->prev->prev; // 获取目标位置的下一个节点
|
||||||
|
curNode->prev = prev; // 删除目标位置的节点
|
||||||
|
prev->next = curNode; // 目标位置的下一个节点的下一个节点指向当前节点
|
||||||
|
}
|
||||||
|
size--; // 链表大小减1
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int size; // 链表的大小
|
||||||
|
DList *sentinelNode; // 哨兵节点的指针
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### C:
|
### C:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
@ -100,6 +100,18 @@ public:
|
|||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
### Java:
|
### Java:
|
||||||
|
排序法
|
||||||
|
```Java
|
||||||
|
class Solution {
|
||||||
|
public int[] sortedSquares(int[] nums) {
|
||||||
|
for (int i = 0; i < nums.length; i++) {
|
||||||
|
nums[i] = nums[i] * nums[i];
|
||||||
|
}
|
||||||
|
Arrays.sort(nums);
|
||||||
|
return nums;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```Java
|
```Java
|
||||||
class Solution {
|
class Solution {
|
||||||
|
@ -366,6 +366,79 @@ public class Main {
|
|||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
|
```Python
|
||||||
|
import collections
|
||||||
|
|
||||||
|
directions = [[-1, 0], [0, 1], [0, -1], [1, 0]]
|
||||||
|
area = 0
|
||||||
|
|
||||||
|
def dfs(i, j, grid, visited, num):
|
||||||
|
global area
|
||||||
|
|
||||||
|
if visited[i][j]:
|
||||||
|
return
|
||||||
|
|
||||||
|
visited[i][j] = True
|
||||||
|
grid[i][j] = num # 标记岛屿号码
|
||||||
|
area += 1
|
||||||
|
|
||||||
|
for x, y in directions:
|
||||||
|
new_x = i + x
|
||||||
|
new_y = j + y
|
||||||
|
if (
|
||||||
|
0 <= new_x < len(grid)
|
||||||
|
and 0 <= new_y < len(grid[0])
|
||||||
|
and grid[new_x][new_y] == "1"
|
||||||
|
):
|
||||||
|
dfs(new_x, new_y, grid, visited, num)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
global area
|
||||||
|
|
||||||
|
N, M = map(int, input().strip().split())
|
||||||
|
grid = []
|
||||||
|
for i in range(N):
|
||||||
|
grid.append(input().strip().split())
|
||||||
|
visited = [[False] * M for _ in range(N)]
|
||||||
|
rec = collections.defaultdict(int)
|
||||||
|
|
||||||
|
cnt = 2
|
||||||
|
for i in range(N):
|
||||||
|
for j in range(M):
|
||||||
|
if grid[i][j] == "1":
|
||||||
|
area = 0
|
||||||
|
dfs(i, j, grid, visited, cnt)
|
||||||
|
rec[cnt] = area # 纪录岛屿面积
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
res = 0
|
||||||
|
for i in range(N):
|
||||||
|
for j in range(M):
|
||||||
|
if grid[i][j] == "0":
|
||||||
|
max_island = 1 # 将水变为陆地,故从1开始计数
|
||||||
|
v = set()
|
||||||
|
for x, y in directions:
|
||||||
|
new_x = i + x
|
||||||
|
new_y = j + y
|
||||||
|
if (
|
||||||
|
0 <= new_x < len(grid)
|
||||||
|
and 0 <= new_y < len(grid[0])
|
||||||
|
and grid[new_x][new_y] != "0"
|
||||||
|
and grid[new_x][new_y] not in v # 岛屿不可重复
|
||||||
|
):
|
||||||
|
max_island += rec[grid[new_x][new_y]]
|
||||||
|
v.add(grid[new_x][new_y])
|
||||||
|
res = max(res, max_island)
|
||||||
|
|
||||||
|
if res == 0:
|
||||||
|
return max(rec.values()) # 无水的情况
|
||||||
|
return res
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(main())
|
||||||
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
### Rust
|
### Rust
|
||||||
|
@ -158,7 +158,62 @@ int main() {
|
|||||||
|
|
||||||
## 其他语言版本
|
## 其他语言版本
|
||||||
|
|
||||||
### Java
|
### Java
|
||||||
|
|
||||||
|
```Java
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Main{
|
||||||
|
public static void main(String[] args) {
|
||||||
|
int N, M;
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
N = scanner.nextInt();
|
||||||
|
M = scanner.nextInt();
|
||||||
|
DisJoint disJoint = new DisJoint(N + 1);
|
||||||
|
for (int i = 0; i < M; ++i) {
|
||||||
|
disJoint.join(scanner.nextInt(), scanner.nextInt());
|
||||||
|
}
|
||||||
|
if(disJoint.isSame(scanner.nextInt(), scanner.nextInt())) {
|
||||||
|
System.out.println("1");
|
||||||
|
} else {
|
||||||
|
System.out.println("0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//并查集模板
|
||||||
|
class DisJoint{
|
||||||
|
private int[] father;
|
||||||
|
|
||||||
|
public DisJoint(int N) {
|
||||||
|
father = new int[N];
|
||||||
|
for (int i = 0; i < N; ++i){
|
||||||
|
father[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int find(int n) {
|
||||||
|
return n == father[n] ? n : (father[n] = find(father[n]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join (int n, int m) {
|
||||||
|
n = find(n);
|
||||||
|
m = find(m);
|
||||||
|
if (n == m) return;
|
||||||
|
father[m] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSame(int n, int m){
|
||||||
|
n = find(n);
|
||||||
|
m = find(m);
|
||||||
|
return n == m;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
|
||||||
|
@ -141,6 +141,70 @@ int main() {
|
|||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const r1 = require('readline').createInterface({ input: process.stdin });
|
||||||
|
// 创建readline接口
|
||||||
|
let iter = r1[Symbol.asyncIterator]();
|
||||||
|
// 创建异步迭代器
|
||||||
|
const readline = async () => (await iter.next()).value;
|
||||||
|
|
||||||
|
|
||||||
|
let N // 节点数和边数
|
||||||
|
let father = [] // 并查集
|
||||||
|
|
||||||
|
|
||||||
|
// 并查集初始化
|
||||||
|
const init = () => {
|
||||||
|
for (let i = 1; i <= N; i++) father[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 并查集里寻根的过程
|
||||||
|
const find = (u) => {
|
||||||
|
return u == father[u] ? u : father[u] = find(father[u])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将v->u 这条边加入并查集
|
||||||
|
const join = (u, v) => {
|
||||||
|
u = find(u)
|
||||||
|
v = find(v)
|
||||||
|
if (u == v) return // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
|
||||||
|
father[v] = u
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断 u 和 v是否找到同一个根
|
||||||
|
const isSame = (u, v) => {
|
||||||
|
u = find(u)
|
||||||
|
v = find(v)
|
||||||
|
return u == v
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
// 读取第一行输入
|
||||||
|
let line = await readline();
|
||||||
|
N = Number(line);
|
||||||
|
|
||||||
|
// 初始化并查集
|
||||||
|
father = new Array(N)
|
||||||
|
init()
|
||||||
|
|
||||||
|
// 读取边信息, 加入并查集
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
line = await readline()
|
||||||
|
line = line.split(' ').map(Number)
|
||||||
|
|
||||||
|
if (!isSame(line[0], line[1])) {
|
||||||
|
join(line[0], line[1])
|
||||||
|
}else{
|
||||||
|
console.log(line[0], line[1]);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### TypeScript
|
### TypeScript
|
||||||
|
|
||||||
### PhP
|
### PhP
|
||||||
|
@ -217,6 +217,38 @@ public class Main {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Python
|
### Python
|
||||||
|
```Python
|
||||||
|
def judge(s1,s2):
|
||||||
|
count=0
|
||||||
|
for i in range(len(s1)):
|
||||||
|
if s1[i]!=s2[i]:
|
||||||
|
count+=1
|
||||||
|
return count==1
|
||||||
|
|
||||||
|
if __name__=='__main__':
|
||||||
|
n=int(input())
|
||||||
|
beginstr,endstr=map(str,input().split())
|
||||||
|
if beginstr==endstr:
|
||||||
|
print(0)
|
||||||
|
exit()
|
||||||
|
strlist=[]
|
||||||
|
for i in range(n):
|
||||||
|
strlist.append(input())
|
||||||
|
|
||||||
|
# use bfs
|
||||||
|
visit=[False for i in range(n)]
|
||||||
|
queue=[[beginstr,1]]
|
||||||
|
while queue:
|
||||||
|
str,step=queue.pop(0)
|
||||||
|
if judge(str,endstr):
|
||||||
|
print(step+1)
|
||||||
|
exit()
|
||||||
|
for i in range(n):
|
||||||
|
if visit[i]==False and judge(strlist[i],str):
|
||||||
|
visit[i]=True
|
||||||
|
queue.append([strlist[i],step+1])
|
||||||
|
print(0)
|
||||||
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@
|
|||||||
|
|
||||||
理解思想后,确实不难,但代码写起来也不容易。
|
理解思想后,确实不难,但代码写起来也不容易。
|
||||||
|
|
||||||
为了每次可以找到所有节点的入度信息,我们要在初始话的时候,就把每个节点的入度 和 每个节点的依赖关系做统计。
|
为了每次可以找到所有节点的入度信息,我们要在初始化的时候,就把每个节点的入度 和 每个节点的依赖关系做统计。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
@ -451,6 +451,80 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
### Javascript
|
### Javascript
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const r1 = require('readline').createInterface({ input: process.stdin });
|
||||||
|
// 创建readline接口
|
||||||
|
let iter = r1[Symbol.asyncIterator]();
|
||||||
|
// 创建异步迭代器
|
||||||
|
const readline = async () => (await iter.next()).value;
|
||||||
|
|
||||||
|
|
||||||
|
let N, M // 节点数和边数
|
||||||
|
let inDegrees = [] // 入度
|
||||||
|
let umap = new Map() // 记录文件依赖关系
|
||||||
|
let result = [] // 结果
|
||||||
|
|
||||||
|
|
||||||
|
// 根据输入, 初始化数据
|
||||||
|
const init = async () => {
|
||||||
|
// 读取第一行输入
|
||||||
|
let line = await readline();
|
||||||
|
[N, M] = line.split(' ').map(Number)
|
||||||
|
|
||||||
|
inDegrees = new Array(N).fill(0)
|
||||||
|
|
||||||
|
// 读取边集
|
||||||
|
while (M--) {
|
||||||
|
line = await readline();
|
||||||
|
let [x, y] = line.split(' ').map(Number)
|
||||||
|
|
||||||
|
// 记录入度
|
||||||
|
inDegrees[y]++
|
||||||
|
|
||||||
|
// 记录x指向哪些文件
|
||||||
|
if (!umap.has(x)) {
|
||||||
|
umap.set(x, [y])
|
||||||
|
} else {
|
||||||
|
umap.get(x).push(y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function () {
|
||||||
|
// 根据输入, 初始化数据
|
||||||
|
await init()
|
||||||
|
|
||||||
|
let queue = [] // 入度为0的节点
|
||||||
|
for (let i = 0; i < N; i++) {
|
||||||
|
if (inDegrees[i] == 0) {
|
||||||
|
queue.push(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queue.length) {
|
||||||
|
let cur = queue.shift() //当前文件
|
||||||
|
|
||||||
|
result.push(cur)
|
||||||
|
|
||||||
|
let files = umap.get(cur) // 当前文件指向的文件
|
||||||
|
|
||||||
|
// 当前文件指向的文件入度减1
|
||||||
|
if (files && files.length) {
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
inDegrees[files[i]]--
|
||||||
|
if (inDegrees[files[i]] == 0) queue.push(files[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这里result.length == N 一定要判断, 因为可能存在环
|
||||||
|
if (result.length == N) return console.log(result.join(' '))
|
||||||
|
console.log(-1)
|
||||||
|
})()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### TypeScript
|
### TypeScript
|
||||||
|
|
||||||
### PhP
|
### PhP
|
||||||
|
@ -193,7 +193,7 @@ dp[0][j],即:i为0,存放编号0的物品的时候,各个容量的背包
|
|||||||
|
|
||||||
代码初始化如下:
|
代码初始化如下:
|
||||||
|
|
||||||
```
|
```CPP
|
||||||
for (int j = 0 ; j < weight[0]; j++) { // 当然这一步,如果把dp数组预先初始化为0了,这一步就可以省略,但很多同学应该没有想清楚这一点。
|
for (int j = 0 ; j < weight[0]; j++) { // 当然这一步,如果把dp数组预先初始化为0了,这一步就可以省略,但很多同学应该没有想清楚这一点。
|
||||||
dp[0][j] = 0;
|
dp[0][j] = 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user