mirror of
https://github.com/labuladong/fucking-algorithm.git
synced 2025-07-05 03:36:39 +08:00
Merge branch 'master' into pr-496
This commit is contained in:
@ -432,3 +432,39 @@ KMP 算法也就是动态规划那点事,我们的公众号文章目录有一
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
[MoguCloud](https://github.com/MoguCloud) 提供 实现 strStr() 的 Python 完整代码:
|
||||
```py
|
||||
class Solution:
|
||||
def strStr(self, haystack: str, needle: str) -> int:
|
||||
# 边界条件判断
|
||||
if not needle:
|
||||
return 0
|
||||
pat = needle
|
||||
txt = haystack
|
||||
|
||||
M = len(pat)
|
||||
# dp[状态][字符] = 下个状态
|
||||
dp = [[0 for _ in range(256)] for _ in pat]
|
||||
# base case
|
||||
dp[0][ord(pat[0])] = 1
|
||||
# 影子状态 X 初始化为 0
|
||||
X = 0
|
||||
for j in range(1, M):
|
||||
for c in range(256):
|
||||
dp[j][c] = dp[X][c]
|
||||
dp[j][ord(pat[j])] = j + 1
|
||||
# 更新影子状态
|
||||
X = dp[X][ord(pat[j])]
|
||||
|
||||
N = len(txt)
|
||||
# pat 初始状态为 0
|
||||
j = 0
|
||||
for i in range(N):
|
||||
# 计算 pat 的下一个状态
|
||||
j = dp[j][ord(txt[i])]
|
||||
# 到达终止态,返回结果
|
||||
if j == M:
|
||||
return i - M + 1
|
||||
# 没到达终止态,匹配失败
|
||||
return -1
|
||||
```
|
||||
|
@ -292,3 +292,30 @@ class Node {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
[ChenjieXu](https://github.com/ChenjieXu) 提供Python版本代码:
|
||||
|
||||
```python3
|
||||
def minDistance(word1, word2):
|
||||
m, n = len(word1), len(word2)
|
||||
# 创建 DP 数组
|
||||
dp = [[0] * (n + 1) for _ in range(m + 1)]
|
||||
|
||||
# base case初始化
|
||||
for i in range(m + 1):
|
||||
dp[i][0] = i
|
||||
for j in range(n + 1):
|
||||
dp[0][j] = j
|
||||
|
||||
# 自底向上求解
|
||||
for i in range(1, m + 1):
|
||||
for j in range(1, n + 1):
|
||||
# 状态转移方程
|
||||
if word1[i - 1] == word2[j - 1]:
|
||||
dp[i][j] = dp[i - 1][j - 1]
|
||||
else:
|
||||
dp[i][j] = min(dp[i - 1][j] + 1,
|
||||
dp[i][j - 1] + 1,
|
||||
dp[i - 1][j - 1] + 1)
|
||||
# 储存着整个 word1 和 word2 的最小编辑距离
|
||||
return dp[m][n]
|
||||
````
|
@ -1,4 +1,4 @@
|
||||
# 贪心算法之区间调度问题
|
||||
# 贪心算法之区间调度问题
|
||||
|
||||
|
||||
<p align='center'>
|
||||
@ -159,3 +159,42 @@ int findMinArrowShots(int[][] intvs) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
### python
|
||||
Edwenc 提供 第435题的python3 代码:
|
||||
|
||||
```python
|
||||
class Solution:
|
||||
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
|
||||
### 思路是首先找到不重叠的区间的个数
|
||||
### 然后再用总个数减去不重叠个数
|
||||
### 获得的就是 需要移除的个数
|
||||
|
||||
# 首先获得区间的个数 为0的话就不用移除
|
||||
n = len(intervals)
|
||||
if n==0:
|
||||
return 0
|
||||
|
||||
# 按照每个区间的右端点值进行排序
|
||||
sorted_list = sorted( intervals , key=lambda x: x[1] )
|
||||
|
||||
# 不重叠区间个数至少是1
|
||||
count = 1
|
||||
|
||||
# end是所有不重叠的区间中 最大的右端点
|
||||
# end的初始值即是sorted_list[0]的右端点
|
||||
end = sorted_list[0][1]
|
||||
|
||||
# 从1开始往后找 因为0在上面已经取过了
|
||||
for i in range(1,n):
|
||||
# start是当前区间左端点值
|
||||
start = sorted_list[i][0]
|
||||
# 如果当前左端点比最大右端点都大了(可能相等)
|
||||
# 说明两区间不重叠 count+1 再更新end
|
||||
if start>=end:
|
||||
count += 1
|
||||
end = sorted_list[i][1]
|
||||
|
||||
# 最后返回的是 需要移除的区间个数
|
||||
return n-count
|
||||
```
|
@ -1,4 +1,4 @@
|
||||
# 二叉搜索树操作集锦
|
||||
# 二叉搜索树操作集锦
|
||||
|
||||
|
||||
<p align='center'>
|
||||
@ -311,8 +311,12 @@ void BST(TreeNode root, int target) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
### c++
|
||||
|
||||
[dekunma](https://www.linkedin.com/in/dekun-ma-036a9b198/)提供第98题C++代码:
|
||||
```C++
|
||||
|
||||
```c++
|
||||
/**
|
||||
* Definition for a binary tree node.
|
||||
* struct TreeNode {
|
||||
@ -343,3 +347,105 @@ public:
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### python
|
||||
|
||||
[ChenjieXu](https://github.com/ChenjieXu)提供第98题Python3代码:
|
||||
|
||||
```python
|
||||
def isValidBST(self, root):
|
||||
# 递归函数
|
||||
def helper(node, lower = float('-inf'), upper = float('inf')):
|
||||
if not node:
|
||||
return True
|
||||
|
||||
val = node.val
|
||||
if val <= lower or val >= upper:
|
||||
return False
|
||||
# 右节点
|
||||
if not helper(node.right, val, upper):
|
||||
return False
|
||||
# 左节点
|
||||
if not helper(node.left, lower, val):
|
||||
return False
|
||||
return True
|
||||
|
||||
return helper(root)
|
||||
|
||||
```
|
||||
|
||||
[lixiandea](https://github.com/lixiandea)提供第100题Python3代码:
|
||||
|
||||
```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 isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
|
||||
'''
|
||||
当前节点值相等且树的子树相等,则树相等。
|
||||
递归退出条件:两个节点存在一个节点为空
|
||||
'''
|
||||
if p == None:
|
||||
if q == None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
if q == None:
|
||||
return False
|
||||
# 当前节点相同且左子树和右子树分别相同
|
||||
return p.val==q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
|
||||
```
|
||||
|
||||
[Edwenc](https://github.com/Edwenc) 提供 leetcode第450题的python3 代码:
|
||||
|
||||
```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 deleteNode(self, root: TreeNode, key: int) -> TreeNode:
|
||||
# 如果没有树 直接返回None
|
||||
if root == None:
|
||||
return None
|
||||
|
||||
# 如果要删除的结点 就是当前结点
|
||||
if root.val == key:
|
||||
# 左子树为空 只有右子树需要被更新 直接返回
|
||||
if root.left == None:
|
||||
return root.right
|
||||
# 右子树为空 只有左子树需要被更新 直接返回
|
||||
if root.right== None:
|
||||
return root.left
|
||||
|
||||
# 找出此结点左子树的最大值
|
||||
# 用这个最大值 来代替当前结点
|
||||
# 再在左子树中递归地删除这个最大值结点
|
||||
big = self.getMax( root.left )
|
||||
root.val = big.val
|
||||
root.left = self.deleteNode( root.left , big.val )
|
||||
|
||||
# 当前结点较大 它的左子树中需要删除节点 递归到左子树
|
||||
elif root.val > key:
|
||||
root.left = self.deleteNode( root.left , key)
|
||||
# 当前结点较小 它的右子树中需要删除节点 递归到右子树
|
||||
else:
|
||||
root.right= self.deleteNode( root.right, key)
|
||||
|
||||
return root
|
||||
|
||||
# 辅助函数
|
||||
# 功能是找出此二叉搜索树中最大元素的结点 并返回此结点
|
||||
def getMax( self , node ):
|
||||
# 一直找它的右子树 直到为空
|
||||
while node.right:
|
||||
node = node.right
|
||||
return node
|
||||
```
|
@ -183,6 +183,8 @@ vector<int> nextGreaterElements(vector<int>& nums) {
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
### java
|
||||
|
||||
[ZakAnun](https://github.com/ZakAnun) 提供代码
|
||||
|
||||
```java
|
||||
@ -236,3 +238,24 @@ public int[] nextGreaterElement(int[] nums1, int[] nums2) {
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```java
|
||||
// 739. Daily Temperatures
|
||||
class Solution {
|
||||
public int[] dailyTemperatures(int[] T) {
|
||||
Stack<Integer> stack = new Stack<>();
|
||||
int[] ans = new int[T.length];
|
||||
for (int i = 0; i < T.length; i++) {
|
||||
// 如果压栈之后不满足单调递减,弹出元素,直至保持单调性
|
||||
while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
|
||||
int index = stack.pop();
|
||||
// 被弹出的元素(T[index])都是小于当前的元素(T[i]),由于栈内元素单调递减,大于被弹出元素(index)的最近的就是当前元素(i)
|
||||
ans[index] = i - index;
|
||||
}
|
||||
stack.push(i);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
```
|
101
数据结构系列/单调队列.md
101
数据结构系列/单调队列.md
@ -211,3 +211,104 @@ vector<int> maxSlidingWindow(vector<int>& nums, int k) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
### python3
|
||||
|
||||
由[SCUHZS](ttps://github.com/brucecat)提供
|
||||
|
||||
|
||||
```python
|
||||
from collections import deque
|
||||
|
||||
class MonotonicQueue(object):
|
||||
def __init__(self):
|
||||
# 双端队列
|
||||
self.data = deque()
|
||||
|
||||
def push(self, n):
|
||||
# 实现单调队列的push方法
|
||||
while self.data and self.data[-1] < n:
|
||||
self.data.pop()
|
||||
self.data.append(n)
|
||||
|
||||
def max(self):
|
||||
# 取得单调队列中的最大值
|
||||
return self.data[0]
|
||||
|
||||
def pop(self, n):
|
||||
# 实现单调队列的pop方法
|
||||
if self.data and self.data[0] == n:
|
||||
self.data.popleft()
|
||||
|
||||
|
||||
class Solution:
|
||||
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
|
||||
# 单调队列实现的窗口
|
||||
window = MonotonicQueue()
|
||||
|
||||
# 结果
|
||||
res = []
|
||||
|
||||
for i in range(0, len(nums)):
|
||||
|
||||
if i < k-1:
|
||||
# 先填满窗口前k-1
|
||||
window.push(nums[i])
|
||||
else:
|
||||
# 窗口向前滑动
|
||||
window.push(nums[i])
|
||||
res.append(window.max())
|
||||
window.pop(nums[i-k+1])
|
||||
return res
|
||||
|
||||
```
|
||||
|
||||
### java
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public int[] maxSlidingWindow(int[] nums, int k) {
|
||||
int len = nums.length;
|
||||
// 判断数组或者窗口长度为0的情况
|
||||
if (len * k == 0) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
/*
|
||||
采用两端扫描的方法
|
||||
将数组分成大小为 k 的若干个窗口, 对每个窗口分别从左往右和从右往左扫描, 记录扫描的最大值
|
||||
left[] 记录从左往右扫描的最大值
|
||||
right[] 记录从右往左扫描的最大值
|
||||
*/
|
||||
int[] left = new int[len];
|
||||
int[] right = new int[len];
|
||||
|
||||
for (int i = 0; i < len; i = i + k) {
|
||||
// 每个窗口中的第一个值
|
||||
left[i] = nums[i];
|
||||
// 窗口的最后边界
|
||||
int index = i + k - 1 >= len ? len - 1 : i + k - 1;
|
||||
// 每个窗口的最后一个值
|
||||
right[index] = nums[index];
|
||||
// 对该窗口从左往右扫描
|
||||
for (int j = i + 1; j <= index; j++) {
|
||||
left[j] = Math.max(left[j - 1], nums[j]);
|
||||
}
|
||||
// 对该窗口从右往左扫描
|
||||
for (int j = index - 1; j >= i; j--) {
|
||||
right[j] = Math.max(right[j + 1], nums[j]);
|
||||
}
|
||||
}
|
||||
|
||||
int[] arr = new int[len - k + 1];
|
||||
|
||||
// 对于第 i 个位置, 它一定是该窗口从右往左扫描数组中的最后一个值, 相对的 i + k - 1 是该窗口从左向右扫描数组中的最后一个位置
|
||||
// 对两者取最大值即可
|
||||
for (int i = 0; i < len - k + 1; i++) {
|
||||
arr[i] = Math.max(right[i], left[i + k - 1]);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -303,3 +303,120 @@ PS:本文前两张图片和 GIF 是我第一次尝试用平板的绘图软件
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[happy-yuxuan](https://github.com/happy-yuxuan) 提供 C++ 代码:
|
||||
|
||||
```c++
|
||||
static int timestamp = 0;
|
||||
class Tweet {
|
||||
private:
|
||||
int id;
|
||||
int time;
|
||||
public:
|
||||
Tweet *next;
|
||||
// id为推文内容,time为发文时间
|
||||
Tweet(int id, int time) {
|
||||
this->id = id;
|
||||
this->time = time;
|
||||
next = nullptr;
|
||||
}
|
||||
int getId() const {
|
||||
return this->id;
|
||||
}
|
||||
int getTime() const {
|
||||
return this->time;
|
||||
}
|
||||
};
|
||||
class User {
|
||||
private:
|
||||
int id;
|
||||
public:
|
||||
Tweet *head; // 发布的Twitter,用链表表示
|
||||
unordered_set<int> followed; // 用户关注了那些人
|
||||
User(int userId) {
|
||||
this->id = userId;
|
||||
head = nullptr;
|
||||
// 要先把自己关注了
|
||||
followed.insert(id);
|
||||
}
|
||||
void follow(int userId) {
|
||||
followed.insert(userId);
|
||||
}
|
||||
void unfollow(int userId) {
|
||||
// 不可以取关自己
|
||||
if (userId != this->id)
|
||||
followed.erase(userId);
|
||||
}
|
||||
void post(int contentId) {
|
||||
Tweet *twt = new Tweet(contentId, timestamp);
|
||||
timestamp++;
|
||||
// 将新建的推文插入链表头
|
||||
// 越靠前的推文 timestamp 值越大
|
||||
twt->next = head;
|
||||
head = twt;
|
||||
}
|
||||
};
|
||||
class Twitter {
|
||||
private:
|
||||
// 映射将 userId 和 User 对象对应起来
|
||||
unordered_map<int, User*> userMap;
|
||||
// 判断该用户存不存在系统中,即userMap中存不存在id
|
||||
inline bool contain(int id) {
|
||||
return userMap.find(id) != userMap.end();
|
||||
}
|
||||
public:
|
||||
Twitter() {
|
||||
userMap.clear();
|
||||
}
|
||||
/* user 发表一条 tweet 动态 */
|
||||
void postTweet(int userId, int tweetId) {
|
||||
if (!contain(userId))
|
||||
userMap[userId] = new User(userId);
|
||||
userMap[userId]->post(tweetId);
|
||||
}
|
||||
/* 返回该 user 关注的人(包括他自己)最近的动态 id,
|
||||
最多 10 条,而且这些动态必须按从新到旧的时间线顺序排列。*/
|
||||
vector<int> getNewsFeed(int userId) {
|
||||
vector<int> ret;
|
||||
if (!contain(userId)) return ret;
|
||||
// 构造一个自动通过Tweet发布的time属性从大到小排序的二叉堆
|
||||
typedef function<bool(const Tweet*, const Tweet*)> Compare;
|
||||
Compare cmp = [](const Tweet *a, const Tweet *b) {
|
||||
return a->getTime() < b->getTime();
|
||||
};
|
||||
priority_queue<Tweet*, vector<Tweet*>, Compare> q(cmp);
|
||||
// 关注列表的用户Id
|
||||
unordered_set<int> &users = userMap[userId]->followed;
|
||||
// 先将所有链表头节点插入优先级队列
|
||||
for (int id : users) {
|
||||
if (!contain(id)) continue;
|
||||
Tweet *twt = userMap[id]->head;
|
||||
if (twt == nullptr) continue;
|
||||
q.push(twt);
|
||||
}
|
||||
while (!q.empty()) {
|
||||
Tweet *t = q.top(); q.pop();
|
||||
ret.push_back(t->getId());
|
||||
if (ret.size() == 10) return ret; // 最多返回 10 条就够了
|
||||
if (t->next)
|
||||
q.push(t->next);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/* follower 关注 followee */
|
||||
void follow(int followerId, int followeeId) {
|
||||
// 若 follower 不存在,则新建
|
||||
if (!contain(followerId))
|
||||
userMap[followerId] = new User(followerId);
|
||||
// 若 followee 不存在,则新建
|
||||
if (!contain(followeeId))
|
||||
userMap[followeeId] = new User(followeeId);
|
||||
userMap[followerId]->follow(followeeId);
|
||||
}
|
||||
/* follower 取关 followee,如果 Id 不存在则什么都不做 */
|
||||
void unfollow(int followerId, int followeeId) {
|
||||
if (contain(followerId))
|
||||
userMap[followerId]->unfollow(followeeId);
|
||||
}
|
||||
};
|
||||
```
|
@ -219,3 +219,39 @@ ListNode reverseBetween(ListNode head, int m, int n) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[DiamondI](https://github.com/DiamondI) 提供python3版本代码:
|
||||
|
||||
思路:递归。时间复杂度为O(n),由于递归调用需要借助栈的空间,因此空间复杂度亦为O(n)。
|
||||
|
||||
```python3
|
||||
# Definition for singly-linked list.
|
||||
# class ListNode:
|
||||
# def __init__(self, val=0, next=None):
|
||||
# self.val = val
|
||||
# self.next = next
|
||||
class Solution:
|
||||
def __init__(self):
|
||||
self.__successor = None
|
||||
|
||||
def __reverseN(self, head: ListNode, n: int) -> ListNode:
|
||||
if n == 1:
|
||||
# 记录第 n + 1 个节点
|
||||
self.__successor = head.next;
|
||||
return head;
|
||||
# 以 head.next 为起点,需要反转前 n - 1 个节点
|
||||
last = self.__reverseN(head.next, n - 1);
|
||||
|
||||
head.next.next = head;
|
||||
# 让反转之后的 head 节点和后面的节点连起来
|
||||
head.next = self.__successor;
|
||||
return last;
|
||||
|
||||
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
|
||||
# base case
|
||||
if m == 1:
|
||||
return self.__reverseN(head, n);
|
||||
# 前进到反转的起点触发 base case
|
||||
head.next = self.reverseBetween(head.next, m - 1, n - 1);
|
||||
return head;
|
||||
```
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
[990.等式方程的可满足性](https://leetcode-cn.com/problems/surrounded-regions)
|
||||
|
||||
[261.以图判树](https://leetcode-cn.com/problems/graph-valid-tree/)
|
||||
|
||||
**-----------**
|
||||
|
||||
上篇文章很多读者对于 Union-Find 算法的应用表示很感兴趣,这篇文章就拿几道 LeetCode 题目来讲讲这个算法的巧妙用法。
|
||||
@ -251,3 +253,77 @@ boolean equationsPossible(String[] equations) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
第261题的Java代码(提供:[LEODPEN](https://github.com/LEODPEN))
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
|
||||
class DisjointSet {
|
||||
|
||||
int count; // 连通分量的总个数
|
||||
int[] parent; // 每个节点的头节点(不一定是连通分量的最终头节点)
|
||||
int[] size; // 每个连通分量的大小
|
||||
|
||||
public DisjointSet(int n) {
|
||||
parent = new int[n];
|
||||
size = new int[n];
|
||||
// 初为n个连通分量,期望最后为1
|
||||
count = n;
|
||||
for (int i = 0; i < n; i++) {
|
||||
// 初始的连通分量只有该节点本身
|
||||
parent[i] = i;
|
||||
size[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param first 节点1
|
||||
* @param second 节点2
|
||||
* @return 未连通 && 连通成功
|
||||
*/
|
||||
public boolean union(int first, int second) {
|
||||
// 分别找到包含first 和 second 的最终根节点
|
||||
int firstParent = findRootParent(first), secondParent = findRootParent(second);
|
||||
// 相等说明已经处于一个连通分量,即说明有环
|
||||
if (firstParent == secondParent) return false;
|
||||
// 将较小的连通分量融入较大的连通分量
|
||||
if (size[firstParent] >= size[secondParent]) {
|
||||
parent[secondParent] = firstParent;
|
||||
size[firstParent] += size[secondParent];
|
||||
} else {
|
||||
parent[firstParent] = secondParent;
|
||||
size[secondParent] += size[firstParent];
|
||||
}
|
||||
// 连通分量已合并,count减少
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node 某节点
|
||||
* @return 包含该节点的连通分量的最终根节点
|
||||
*/
|
||||
private int findRootParent(int node) {
|
||||
while (node != parent[node]) {
|
||||
// 压缩路径
|
||||
parent[node] = parent[parent[node]];
|
||||
node = parent[node];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validTree(int n, int[][] edges) {
|
||||
// 树的特性:节点数 = 边数 + 1
|
||||
if (edges.length != n - 1) return false;
|
||||
DisjointSet djs = new DisjointSet(n);
|
||||
for (int[] edg : edges) {
|
||||
// 判断连通情况(如果合并的两个点在一个连通分量里,说明有环)
|
||||
if (!djs.union(edg[0], edg[1])) return false;
|
||||
}
|
||||
// 是否全部节点均已相连
|
||||
return djs.count == 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -90,5 +90,66 @@ def merge(intervals):
|
||||
<p align='center'>
|
||||
<img src="../pictures/qrcode.jpg" width=200 >
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
~~~java
|
||||
class Solution {
|
||||
/**
|
||||
* 1. 先对区间集合进行排序(根据开始位置)
|
||||
* 2. 合并的情况一共有三种
|
||||
* a. b. c.
|
||||
* |---------| |--------| |--------|
|
||||
* |---------| |--| |--------|
|
||||
* a和b两种情况,合并取右边界大的值,c情况不合并
|
||||
*
|
||||
*/
|
||||
|
||||
private int[][] tmp;
|
||||
|
||||
public int[][] merge(int[][] intervals) {
|
||||
if(intervals == null ||intervals.length == 0)return new int[0][0];
|
||||
int length = intervals.length;
|
||||
//将列表中的区间按照左端点升序排序
|
||||
// Arrays.sort(intervals,(v1,v2) -> v1[0]-v2[0]);
|
||||
|
||||
this.tmp = new int[length][2];
|
||||
sort(intervals,0,length-1);
|
||||
|
||||
int[][] ans = new int[length][2];
|
||||
int index = -1;
|
||||
for(int[] interval:intervals){
|
||||
// 当结果数组是空是,或者当前区间的起始位置 > 结果数组中最后区间的终止位置(即上图情况c);
|
||||
// 则不合并,直接将当前区间加入结果数组。
|
||||
if(index == -1 || interval[0] > ans[index][1]){
|
||||
ans[++index] = interval;
|
||||
}else{
|
||||
// 反之将当前区间合并至结果数组的最后区间(即上图情况a,b)
|
||||
ans[index][1] = Math.max(ans[index][1],interval[1]);
|
||||
}
|
||||
}
|
||||
return Arrays.copyOf(ans, index + 1);
|
||||
}
|
||||
|
||||
//归并排序
|
||||
public void sort(int[][] intervals,int l,int r){
|
||||
if(l >= r)return;
|
||||
|
||||
int mid = l + (r-l)/2;
|
||||
sort(intervals,l,mid);
|
||||
sort(intervals,mid+1,r);
|
||||
|
||||
//合并
|
||||
int i=l,j=mid+1;
|
||||
for(int k=l;k<=r;k++){
|
||||
if(i>mid)tmp[k]=intervals[j++];
|
||||
else if(j>r)tmp[k]=intervals[i++];
|
||||
else if(intervals[i][0]>intervals[j][0])tmp[k] = intervals[j++];
|
||||
else tmp[k] = intervals[i++];
|
||||
}
|
||||
|
||||
System.arraycopy(tmp,l,intervals,l,r-l+1);
|
||||
}
|
||||
|
||||
}
|
||||
~~~
|
||||
|
||||
|
@ -102,3 +102,79 @@ string multiply(string num1, string num2) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
### python
|
||||
|
||||
[fengshuu](https://github.com/fengshuu) 提供 Python 解法代码:
|
||||
```python
|
||||
def multiply(num1: str, num2: str) -> str:
|
||||
m, n = len(num1), len(num2)
|
||||
# 结果最多为 m + n 位数
|
||||
res = [0] * (m + n)
|
||||
# 从个位数开始逐位相乘
|
||||
for i in range(m-1, -1, -1):
|
||||
for j in range(n-1, -1, -1):
|
||||
mul = int(num1[i]) * int(num2[j])
|
||||
# 乘积在 res 对应的索引位置
|
||||
p1 = i + j
|
||||
p2 = i + j + 1
|
||||
# 叠加到 res 上
|
||||
digit_sum = mul + res[p2]
|
||||
res[p2] = digit_sum % 10
|
||||
res[p1] += digit_sum // 10
|
||||
|
||||
# 结果前缀可能存的 0(未使用的位)
|
||||
i = 0
|
||||
while i < len(res) and res[i] == 0:
|
||||
i += 1
|
||||
|
||||
# 将计算结果转化成字符串
|
||||
result_str = "".join(str(x) for x in res[i:])
|
||||
|
||||
return "0" if len(result_str) == 0 else result_str
|
||||
```
|
||||
|
||||
### java
|
||||
|
||||
[Zane Wang](https://github.com/zanecat) 提供 Java 解法代码:
|
||||
```java
|
||||
public String multiply(String num1, String num2) {
|
||||
// 初始化字符数组
|
||||
char[] s1 = num1.toCharArray();
|
||||
char[] s2 = num2.toCharArray();
|
||||
|
||||
// 结果长度最多为两字符串长度之和
|
||||
int[] res = new int[s1.length + s2.length];
|
||||
|
||||
// 从个位开始遍历,把两数字中每一位相乘
|
||||
for (int i = s1.length - 1; i >= 0; i--) {
|
||||
for (int j = s2.length - 1; j >= 0; j--) {
|
||||
// 计算乘积,并把乘积放在 res 对应的位置, 暂时不考虑进位
|
||||
res[i + j + 1] += (s1[i] - '0') * (s2[j] - '0');
|
||||
}
|
||||
}
|
||||
|
||||
// 从个位再次遍历,如果上一次遍历中两数乘积为两位数,进位并叠加到前面一位
|
||||
int carry = 0;
|
||||
for (int i = res.length - 1; i >= 0; i--) {
|
||||
int sum = res[i] + carry;
|
||||
res[i] = sum % 10;
|
||||
carry = sum / 10;
|
||||
}
|
||||
|
||||
//遍历res数组,构造最终答案字符串
|
||||
StringBuilder ans = new StringBuilder();
|
||||
int i = 0;
|
||||
|
||||
// 首先找到不为0的第一位
|
||||
while (i < res.length - 1 && res[i] == 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
// 将后面的数字附加到ans后面
|
||||
while (i < res.length) {
|
||||
ans.append(res[i++]);
|
||||
}
|
||||
return ans.toString();
|
||||
}
|
||||
```
|
@ -372,3 +372,30 @@ class Solution:
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
|
||||
|
||||
第3题 Python3 代码(提供: [FaDrYL](https://github.com/FaDrYL) ):
|
||||
```Python3
|
||||
def lengthOfLongestSubstring(self, s: str) -> int:
|
||||
# 子字符串
|
||||
sub = ""
|
||||
largest = 0
|
||||
|
||||
# 循环字符串,将当前字符加入子字符串,并检查长度
|
||||
for i in range(len(s)):
|
||||
if s[i] not in sub:
|
||||
# 当前字符不存在于子字符串中,加入当前字符
|
||||
sub += s[i]
|
||||
else:
|
||||
# 如果当前子字符串的长度超过了之前的记录
|
||||
if len(sub) > largest:
|
||||
largest = len(sub)
|
||||
# 将子字符串从当前字符处+1切片至最后,并加入当前字符
|
||||
sub = sub[sub.find(s[i])+1:] + s[i]
|
||||
|
||||
# 如果最后的子字符串长度超过了之前的记录
|
||||
if len(sub) > largest:
|
||||
return len(sub)
|
||||
return largest
|
||||
```
|
||||
|
@ -150,3 +150,73 @@ void reverse(int[] arr, int i, int j) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[L-WEIWEI](https://github.com/L-WWEEII) 提供 第969题的 Java 代码:
|
||||
|
||||
```java
|
||||
class Solution {
|
||||
public List<Integer> pancakeSort(int[] A) {
|
||||
List<Integer> ans = new ArrayList<Integer>();
|
||||
int len = A.length;
|
||||
if(len == 0){
|
||||
return ans;
|
||||
}
|
||||
// maxIndex[0] == 当前轮次的最大元素, maxIndex[1] == 最大元素下标
|
||||
int[] maxIndex = new int[2];
|
||||
maxIndex[0] = Integer.MIN_VALUE;
|
||||
int maxCount = 0;
|
||||
// maxCount == len 时,说明完成了整个数组的最大值沉底操作,
|
||||
while(maxCount < len - 1){
|
||||
maxCount = maxValueDown(A, maxIndex, maxCount, ans);
|
||||
// 每做完一次最大值沉底操作,初始化最大元素值
|
||||
maxIndex[0] = Integer.MIN_VALUE;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
public int maxValueDown(int[] A, int[] maxIndex, int maxCount, List<Integer> ans){
|
||||
// 遍历条件为 i < A.length - maxCount , 每次最大值沉底时,maxCount + 1,因此下次遍历即可不对最后 maxCount 个元素做操作
|
||||
for(int i = 0; i < A.length - maxCount; i++){
|
||||
// 元素大于当前储存的元素时,将值与下标 copy 到 maxIndex 数组中
|
||||
if(A[i] > maxIndex[0]){
|
||||
maxIndex[0] = A[i];
|
||||
maxIndex[1] = i;
|
||||
}
|
||||
}
|
||||
// 如果当前轮次最大元素的下标的下一位是上一轮次的最大下标,则不做翻转操作,直接返回 maxCount + 1
|
||||
if(maxIndex[1] + 1 == A.length - maxCount){
|
||||
return maxCount + 1;
|
||||
}
|
||||
// 使用最大值沉底时,当本轮最大值在首位时,不需要再将其先翻转至首位,所以不添加
|
||||
if(maxIndex[1] > 0){
|
||||
// 将该轮次要翻转的下标添加到结果集中,结果集中需要的是翻转的位置而不是下标,所以添加时下标得 + 1
|
||||
ans.add(maxIndex[1] + 1);
|
||||
}
|
||||
// 双指针原地交换数组中的值
|
||||
// 左指针指0
|
||||
int left = 0;
|
||||
// 右指针指向当前轮次最大元素的下标
|
||||
int right = maxIndex[1];
|
||||
while(left < right){
|
||||
// 交换元素值
|
||||
A[left] += A[right];
|
||||
A[right] = A[left] - A[right];
|
||||
A[left] -= A[right];
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
// 上面交换玩元素值后,当前轮次最大元素排在首位,再从上一轮次最大元素 - 1 的位置翻转
|
||||
// 则当前轮次的最大元素成功沉底
|
||||
ans.add(A.length - maxCount);
|
||||
left = 0;
|
||||
right = A.length - 1 - maxCount;
|
||||
while(left < right){
|
||||
A[left] += A[right];
|
||||
A[right] = A[left] - A[right];
|
||||
A[left] -= A[right];
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
return maxCount + 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -347,6 +347,93 @@ class LRUCache {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[gowufang](https://github.com/gowufang)提供第146题C++代码:
|
||||
```cpp
|
||||
class LRUCache {
|
||||
public:
|
||||
struct node {
|
||||
int val;
|
||||
int key;
|
||||
node* pre;//当前节点的前一个节点
|
||||
node* next;//当前节点的后一个节点
|
||||
node(){}
|
||||
node(int key, int val):key(key), val(val), pre(NULL), next(NULL){}
|
||||
};
|
||||
|
||||
LRUCache(int size) {
|
||||
this->size = size;
|
||||
head = new node();
|
||||
tail = new node();
|
||||
head->next = tail;
|
||||
tail->pre = head;
|
||||
}
|
||||
|
||||
|
||||
void movetohead(node* cur)//相当于一个insert操作,在head 和 head的next之间插入一个节点
|
||||
{
|
||||
node* next = head->next;//head的next先保存起来
|
||||
head->next = cur;//将当前节点移动到head的后面
|
||||
cur->pre = head;//当前节点cur的pre指向head
|
||||
next->pre = cur;
|
||||
cur->next = next;
|
||||
}
|
||||
|
||||
node* deletecurrentnode(node* cur)//移除当前节点
|
||||
{
|
||||
cur->pre->next = cur->next;
|
||||
cur->next->pre = cur->pre;
|
||||
return cur;
|
||||
}
|
||||
void makerecently(node* cur)
|
||||
{
|
||||
node* temp = deletecurrentnode(cur);// 删除 cur,要重新插入到对头
|
||||
movetohead(temp);//cur放到队头去
|
||||
}
|
||||
int get(int key)
|
||||
{
|
||||
int ret = -1;
|
||||
if ( map.count(key))
|
||||
{
|
||||
node* temp = map[key];
|
||||
makerecently(temp);// 将 key 变为最近使用
|
||||
ret = temp->val;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void put(int key, int value) {
|
||||
if ( map.count(key))
|
||||
{
|
||||
// 修改 key 的值
|
||||
node* temp = map[key];
|
||||
temp->val = value;
|
||||
// 将 key 变为最近使用
|
||||
makerecently(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
node* cur = new node(key, value);
|
||||
if( map.size()== size )
|
||||
{
|
||||
// 链表头部就是最久未使用的 key
|
||||
node *temp = deletecurrentnode(tail->pre);
|
||||
map.erase(temp->key);
|
||||
}
|
||||
movetohead(cur);
|
||||
map[key] = cur;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unordered_map<int, node*> map;
|
||||
int size;
|
||||
node* head, *tail;
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
```python3
|
||||
"""
|
||||
所谓LRU缓存,根本的难点在于记录最久被使用的键值对,这就设计到排序的问题,
|
||||
|
@ -170,3 +170,80 @@ for (int i = 0; i < n; i++)
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
#### c++
|
||||
[cchroot](https://github.com/cchroot) 提供 C++ 代码:
|
||||
|
||||
```c++
|
||||
class Solution {
|
||||
public:
|
||||
int minEatingSpeed(vector<int>& piles, int H) {
|
||||
// 二分法查找最小速度
|
||||
// 初始化最小速度为 1,最大速度为题目设定的最大值 10^9
|
||||
// 这里也可以遍历 piles 数组,获取数组中的最大值,设置 right 为数组中的最大值即可(因为每堆香蕉1小时吃完是最快的)
|
||||
// log2(10^9) 约等于30,次数不多,所以这里暂时就不采取遍历获取最大值了
|
||||
int left = 1, right = pow(10, 9);
|
||||
while (left < right) { // 二分法基本的防止溢出
|
||||
int mid = left + (right - left) / 2;
|
||||
// 以 mid 的速度吃香蕉,是否能在 H 小时内吃完香蕉
|
||||
if (!canFinish(piles, mid, H))
|
||||
left = mid + 1;
|
||||
else
|
||||
right = mid;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
// 以 speed 的速度是否能把香蕉吃完
|
||||
bool canFinish(vector<int>& piles, int speed, int H) {
|
||||
int time = 0;
|
||||
// 遍历累加时间 time
|
||||
for (int p: piles)
|
||||
time += (p - 1) / speed + 1;
|
||||
return time <= H; // time 小于等于 H 说明能在 H 小时吃完返回 true, 否则返回 false
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### python
|
||||
[tonytang731](https://https://github.com/tonytang731) 提供 Python3 代码:
|
||||
|
||||
```python
|
||||
import math
|
||||
|
||||
class Solution:
|
||||
def minEatingSpeed(self, piles, H):
|
||||
# 初始化起点和终点, 最快的速度可以一次拿完最大的一堆
|
||||
start = 1
|
||||
end = max(piles)
|
||||
|
||||
# while loop进行二分查找
|
||||
while start + 1 < end:
|
||||
mid = start + (end - start) // 2
|
||||
|
||||
# 如果中点所需时间大于H, 我们需要加速, 将起点设为中点
|
||||
if self.timeH(piles, mid) > H:
|
||||
start = mid
|
||||
# 如果中点所需时间小于H, 我们需要减速, 将终点设为中点
|
||||
else:
|
||||
end = mid
|
||||
|
||||
# 提交前确认起点是否满足条件,我们要尽量慢拿
|
||||
if self.timeH(piles, start) <= H:
|
||||
return start
|
||||
|
||||
# 若起点不符合, 则中点是答案
|
||||
return end
|
||||
|
||||
|
||||
|
||||
def timeH(self, piles, K):
|
||||
# 初始化时间
|
||||
H = 0
|
||||
|
||||
#求拿每一堆需要多长时间
|
||||
for pile in piles:
|
||||
H += math.ceil(pile / K)
|
||||
|
||||
return H
|
||||
```
|
||||
|
@ -169,3 +169,66 @@ boolean isSubsequence(String s, String t) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
[dekunma](https://www.linkedin.com/in/dekun-ma-036a9b198/) 提供C++代码
|
||||
**解法一:遍历(也可以用双指针):**
|
||||
```C++
|
||||
class Solution {
|
||||
public:
|
||||
bool isSubsequence(string s, string t) {
|
||||
// 遍历s
|
||||
for(int i = 0; i < s.size(); i++) {
|
||||
// 找到s[i]字符在t中的位置
|
||||
size_t pos = t.find(s[i]);
|
||||
|
||||
// 如果s[i]字符不在t中,返回false
|
||||
if(pos == std::string::npos) return false;
|
||||
// 如果s[i]在t中,后面就只看pos以后的字串,防止重复查找
|
||||
else t = t.substr(pos + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**解法二:二分查找:**
|
||||
```C++
|
||||
class Solution {
|
||||
public:
|
||||
bool isSubsequence(string s, string t) {
|
||||
int m = s.size(), n = t.size();
|
||||
// 对 t 进行预处理
|
||||
vector<int> index[256];
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = t[i];
|
||||
index[c].push_back(i);
|
||||
}
|
||||
// 串 t 上的指针
|
||||
int j = 0;
|
||||
// 借助 index 查找 s[i]
|
||||
for (int i = 0; i < m; i++) {
|
||||
char c = s[i];
|
||||
// 整个 t 压根儿没有字符 c
|
||||
if (index[c].empty()) return false;
|
||||
int pos = left_bound(index[c], j);
|
||||
// 二分搜索区间中没有找到字符 c
|
||||
if (pos == index[c].size()) return false;
|
||||
// 向前移动指针 j
|
||||
j = index[c][pos] + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 查找左侧边界的二分查找
|
||||
int left_bound(vector<int> arr, int tar) {
|
||||
int lo = 0, hi = arr.size();
|
||||
while (lo < hi) {
|
||||
int mid = lo + (hi - lo) / 2;
|
||||
if (tar > arr[mid]) {
|
||||
lo = mid + 1;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
@ -238,3 +238,34 @@ p.next = reverse(q);
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
C++版本:
|
||||
```cpp
|
||||
bool isPalindrome(ListNode* head) {
|
||||
if (head == nullptr || head->next == nullptr) //为空或者只有一个节点时,直接判断为true
|
||||
return true;
|
||||
ListNode* slow = head, * fast = head;
|
||||
while (fast != nullptr) {//首先找到中间节点
|
||||
slow = slow->next;
|
||||
fast = fast->next == nullptr? fast->next:fast->next->next; //因为链表长度可能是奇数或偶数,所以需要进行判断
|
||||
}
|
||||
|
||||
ListNode* temp = nullptr,* pre = nullptr;//pre始终保持后续链表的头部,temp节点则作为中间零时替换的节点
|
||||
while (slow != nullptr) {//利用头插法,将当前节点与后续链表断链处理,反转后半部分的链表
|
||||
temp = slow->next;
|
||||
slow->next = pre;//建立连接
|
||||
pre = slow;//pre始终作为后续链表的头部
|
||||
slow = temp;
|
||||
}
|
||||
|
||||
while (head !=nullptr && pre != nullptr) {//同步进行比较
|
||||
if (head->val != pre->val) {//值有不一样的,说明不是回文联表,直接返回false了
|
||||
return false;
|
||||
}
|
||||
head = head->next;//head向下走,直到走到空
|
||||
pre = pre->next;//pre节点也向下走,直到走到空
|
||||
}
|
||||
return true;//到此说明当前链表是回文链表返回true即可
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -283,5 +283,42 @@ void backtrack(int[] nums, LinkedList<Integer> track) {
|
||||
<p align='center'>
|
||||
<img src="../pictures/qrcode.jpg" width=200 >
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[userLF](https://github.com/userLF)提供全排列的java代码:
|
||||
|
||||
```java
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class Solution {
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
public List<List<Integer>> permute(int[] nums) {
|
||||
res.clear();
|
||||
dfs(nums, 0);//
|
||||
return res;
|
||||
}
|
||||
|
||||
public void dfs(int[] n, int start) {//start表示要被替换元素的位置
|
||||
if( start >= n.length) {
|
||||
List<Integer> list = new ArrayList<Integer>();
|
||||
for(int i : n) {
|
||||
list.add(i);
|
||||
}
|
||||
res.add(list);
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = start; i< n.length; i++) {//i从start开始,如果从start+1开始的话,会把当前序列遗漏掉直接保存了下一个序列
|
||||
int temp= n[i];
|
||||
n[i] = n[start];
|
||||
n[start] = temp;
|
||||
dfs(n, start + 1);//递归下一个位置
|
||||
//回到上一个状态
|
||||
n[start] = n[i];
|
||||
n[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
@ -132,3 +132,39 @@ string longestPalindrome(string s) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[cchromt](https://github.com/cchroot) 提供 Java 代码:
|
||||
|
||||
```java
|
||||
// 中心扩展算法
|
||||
class Solution {
|
||||
public String longestPalindrome(String s) {
|
||||
// 如果字符串长度小于2,则直接返回其本身
|
||||
if (s.length() < 2) {
|
||||
return s;
|
||||
}
|
||||
String res = "";
|
||||
for (int i = 0; i < s.length() - 1; i++) {
|
||||
// 以 s.charAt(i) 为中心的最长回文子串
|
||||
String s1 = palindrome(s, i, i);
|
||||
// 以 s.charAt(i) 和 s.charAt(i+1) 为中心的最长回文子串
|
||||
String s2 = palindrome(s, i, i + 1);
|
||||
res = res.length() > s1.length() ? res : s1;
|
||||
res = res.length() > s2.length() ? res : s2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public String palindrome(String s, int left, int right) {
|
||||
// 索引未越界的情况下,s.charAt(left) == s.charAt(right) 则继续向两边拓展
|
||||
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
|
||||
left--;
|
||||
right++;
|
||||
}
|
||||
// 这里要注意,跳出 while 循环时,恰好满足 s.charAt(i) != s.charAt(j),因此截取的的字符串为[left+1, right-1]
|
||||
return s.substring(left + 1, right);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
做完这题,大家可以去看看 [647. 回文子串](https://leetcode-cn.com/problems/palindromic-substrings/) ,也是类似的题目
|
||||
|
@ -89,6 +89,7 @@ int missingNumber(int[] nums) {
|
||||
for (int x : nums)
|
||||
sum += x;
|
||||
return expect - sum;
|
||||
}
|
||||
```
|
||||
|
||||
你看,这种解法应该是最简单的,但说实话,我自己也没想到这个解法,而且我去问了几个大佬,他们也没想到这个最简单的思路。相反,如果去问一个初中生,他也许很快就能想到。
|
||||
@ -133,3 +134,48 @@ public int missingNumber(int[] nums) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[happy-yuxuan](https://github.com/happy-yuxuan) 提供 三种方法的 C++ 代码:
|
||||
|
||||
```c++
|
||||
// 方法:异或元素和索引
|
||||
int missingNumber(vector<int>& nums) {
|
||||
int n = nums.size();
|
||||
int res = 0;
|
||||
// 先和新补的索引异或一下
|
||||
res ^= n;
|
||||
// 和其他的元素、索引做异或
|
||||
for (int i = 0; i < n; i++)
|
||||
res ^= i ^ nums[i];
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
```c++
|
||||
// 方法:等差数列求和
|
||||
int missingNumber(vector<int>& nums) {
|
||||
int n = nums.size();
|
||||
// 公式:(首项 + 末项) * 项数 / 2
|
||||
int expect = (0 + n) * (n + 1) / 2;
|
||||
int sum = 0;
|
||||
for (int x : nums)
|
||||
sum += x;
|
||||
return expect - sum;
|
||||
}
|
||||
```
|
||||
|
||||
```c++
|
||||
// 方法:防止整型溢出
|
||||
int missingNumber(vector<int>& nums) {
|
||||
int n = nums.size();
|
||||
int res = 0;
|
||||
// 新补的索引
|
||||
res += n - 0;
|
||||
// 剩下索引和元素的差加起来
|
||||
for (int i = 0; i < n; i++)
|
||||
res += i - nums[i];
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
@ -140,3 +140,29 @@ vector<int> findErrorNums(vector<int>& nums) {
|
||||
</p>
|
||||
|
||||
======其他语言代码======
|
||||
|
||||
[zhuli](https://github.com/1097452462 "zhuli")提供的Java代码:
|
||||
```java
|
||||
class Solution {
|
||||
public int[] findErrorNums(int[] nums) {
|
||||
int n = nums.length;
|
||||
int dup = -1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
// 元素是从 1 开始的
|
||||
int index = Math.abs(nums[i]) - 1;
|
||||
// nums[index] 小于 0 则说明重复访问
|
||||
if (nums[index] < 0)
|
||||
dup = Math.abs(nums[i]);
|
||||
else
|
||||
nums[index] *= -1;
|
||||
}
|
||||
int missing = -1;
|
||||
for (int i = 0; i < n; i++)
|
||||
// nums[i] 大于 0 则说明没有访问
|
||||
if (nums[i] > 0)
|
||||
// 将索引转换成元素
|
||||
missing = i + 1;
|
||||
return new int[]{dup, missing};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
Reference in New Issue
Block a user