mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-09 19:44:45 +08:00
Merge branch 'youngyangyang04:master' into master
This commit is contained in:
@ -186,6 +186,24 @@ var twoSum = function (nums, target) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function twoSum(nums: number[], target: number): number[] {
|
||||
let helperMap: Map<number, number> = new Map();
|
||||
let index: number | undefined;
|
||||
let resArr: number[] = [];
|
||||
for (let i = 0, length = nums.length; i < length; i++) {
|
||||
index = helperMap.get(target - nums[i]);
|
||||
if (index !== undefined) {
|
||||
resArr = [i, index];
|
||||
}
|
||||
helperMap.set(nums[i], i);
|
||||
}
|
||||
return resArr;
|
||||
};
|
||||
```
|
||||
|
||||
php
|
||||
|
||||
```php
|
||||
|
@ -332,7 +332,43 @@ var threeSum = function(nums) {
|
||||
return res;
|
||||
};
|
||||
```
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function threeSum(nums: number[]): number[][] {
|
||||
nums.sort((a, b) => a - b);
|
||||
let length = nums.length;
|
||||
let left: number = 0,
|
||||
right: number = length - 1;
|
||||
let resArr: number[][] = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (i > 0 && nums[i] === nums[i - 1]) {
|
||||
continue;
|
||||
}
|
||||
left = i + 1;
|
||||
right = length - 1;
|
||||
while (left < right) {
|
||||
let total: number = nums[i] + nums[left] + nums[right];
|
||||
if (total === 0) {
|
||||
resArr.push([nums[i], nums[left], nums[right]]);
|
||||
left++;
|
||||
right--;
|
||||
while (nums[right] === nums[right + 1]) {
|
||||
right--;
|
||||
}
|
||||
while (nums[left] === nums[left - 1]) {
|
||||
left++;
|
||||
}
|
||||
} else if (total < 0) {
|
||||
left++;
|
||||
} else {
|
||||
right--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return resArr;
|
||||
};
|
||||
```
|
||||
|
||||
ruby:
|
||||
```ruby
|
||||
|
@ -311,7 +311,49 @@ var fourSum = function(nums, target) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function fourSum(nums: number[], target: number): number[][] {
|
||||
nums.sort((a, b) => a - b);
|
||||
let first: number = 0,
|
||||
second: number,
|
||||
third: number,
|
||||
fourth: number;
|
||||
let length: number = nums.length;
|
||||
let resArr: number[][] = [];
|
||||
for (; first < length; first++) {
|
||||
if (first > 0 && nums[first] === nums[first - 1]) {
|
||||
continue;
|
||||
}
|
||||
for (second = first + 1; second < length; second++) {
|
||||
if ((second - first) > 1 && nums[second] === nums[second - 1]) {
|
||||
continue;
|
||||
}
|
||||
third = second + 1;
|
||||
fourth = length - 1;
|
||||
while (third < fourth) {
|
||||
let total: number = nums[first] + nums[second] + nums[third] + nums[fourth];
|
||||
if (total === target) {
|
||||
resArr.push([nums[first], nums[second], nums[third], nums[fourth]]);
|
||||
third++;
|
||||
fourth--;
|
||||
while (nums[third] === nums[third - 1]) third++;
|
||||
while (nums[fourth] === nums[fourth + 1]) fourth--;
|
||||
} else if (total < target) {
|
||||
third++;
|
||||
} else {
|
||||
fourth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return resArr;
|
||||
};
|
||||
```
|
||||
|
||||
PHP:
|
||||
|
||||
```php
|
||||
class Solution {
|
||||
/**
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||

|
||||
|
||||
很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。
|
||||
很明显暴力解法的时间复杂度是$O(n^2)$,这道题目暴力解法在leetcode上是可以过的。
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -259,7 +259,7 @@ void getNext(int* next, const string& s)
|
||||
|
||||
然后还要对next数组进行初始化赋值,如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
int j = -1;
|
||||
next[0] = j;
|
||||
```
|
||||
@ -278,8 +278,8 @@ next[i] 表示 i(包括i)之前最长相等的前后缀长度(其实就是
|
||||
|
||||
所以遍历模式串s的循环下标i 要从 1开始,代码如下:
|
||||
|
||||
```
|
||||
for(int i = 1; i < s.size(); i++) {
|
||||
```cpp
|
||||
for (int i = 1; i < s.size(); i++) {
|
||||
```
|
||||
|
||||
如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
|
||||
@ -292,7 +292,7 @@ next[j]就是记录着j(包括j)之前的子串的相同前后缀的长度
|
||||
|
||||
所以,处理前后缀不相同的情况代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
|
||||
j = next[j]; // 向前回退
|
||||
}
|
||||
@ -300,7 +300,7 @@ while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
|
||||
|
||||
3. 处理前后缀相同的情况
|
||||
|
||||
如果s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
|
||||
如果 s[i] 与 s[j + 1] 相同,那么就同时向后移动i 和j 说明找到了相同的前后缀,同时还要将j(前缀的长度)赋给next[i], 因为next[i]要记录相同前后缀的长度。
|
||||
|
||||
代码如下:
|
||||
|
||||
@ -346,7 +346,7 @@ void getNext(int* next, const string& s){
|
||||
|
||||
i就从0开始,遍历文本串,代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
for (int i = 0; i < s.size(); i++)
|
||||
```
|
||||
|
||||
@ -356,7 +356,7 @@ for (int i = 0; i < s.size(); i++)
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
while(j >= 0 && s[i] != t[j + 1]) {
|
||||
j = next[j];
|
||||
}
|
||||
@ -364,7 +364,7 @@ while(j >= 0 && s[i] != t[j + 1]) {
|
||||
|
||||
如果 s[i] 与 t[j + 1] 相同,那么i 和 j 同时向后移动, 代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
if (s[i] == t[j + 1]) {
|
||||
j++; // i的增加在for循环里
|
||||
}
|
||||
@ -376,7 +376,7 @@ if (s[i] == t[j + 1]) {
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
if (j == (t.size() - 1) ) {
|
||||
return (i - t.size() + 1);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
模拟的队列执行语句如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
queue.pop(); // 注意弹出的操作
|
||||
|
@ -21,7 +21,7 @@ empty() -- 返回队列是否为空。
|
||||
|
||||
示例:
|
||||
|
||||
```
|
||||
```cpp
|
||||
MyQueue queue = new MyQueue();
|
||||
queue.push(1);
|
||||
queue.push(2);
|
||||
|
@ -142,7 +142,7 @@ class Solution {
|
||||
|
||||
Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
|
||||
// 根据map的value值正序排,相当于一个小顶堆
|
||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o2.getValue() - o1.getValue());
|
||||
PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<>((o1, o2) -> o1.getValue() - o2.getValue());
|
||||
for (Map.Entry<Integer, Integer> entry : entries) {
|
||||
queue.offer(entry);
|
||||
if (queue.size() > k) {
|
||||
|
@ -264,6 +264,27 @@ var canConstruct = function(ransomNote, magazine) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function canConstruct(ransomNote: string, magazine: string): boolean {
|
||||
let helperArr: number[] = new Array(26).fill(0);
|
||||
let base: number = 'a'.charCodeAt(0);
|
||||
let index: number;
|
||||
for (let i = 0, length = magazine.length; i < length; i++) {
|
||||
helperArr[magazine[i].charCodeAt(0) - base]++;
|
||||
}
|
||||
for (let i = 0, length = ransomNote.length; i < length; i++) {
|
||||
index = ransomNote[i].charCodeAt(0) - base;
|
||||
helperArr[index]--;
|
||||
if (helperArr[index] < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
PHP:
|
||||
```php
|
||||
|
@ -192,8 +192,33 @@ var fourSumCount = function(nums1, nums2, nums3, nums4) {
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript:
|
||||
|
||||
```typescript
|
||||
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
|
||||
let helperMap: Map<number, number> = new Map();
|
||||
let resNum: number = 0;
|
||||
let tempVal: number | undefined;
|
||||
for (let i of nums1) {
|
||||
for (let j of nums2) {
|
||||
tempVal = helperMap.get(i + j);
|
||||
helperMap.set(i + j, tempVal ? tempVal + 1 : 1);
|
||||
}
|
||||
}
|
||||
for (let k of nums3) {
|
||||
for (let l of nums4) {
|
||||
tempVal = helperMap.get(0 - (k + l));
|
||||
if (tempVal) {
|
||||
resNum += tempVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return resNum;
|
||||
};
|
||||
```
|
||||
|
||||
PHP:
|
||||
|
||||
```php
|
||||
class Solution {
|
||||
/**
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
## 思路
|
||||
|
||||
### 动态规划一
|
||||
|
||||
本题和[动态规划:115.不同的子序列](https://programmercarl.com/0115.不同的子序列.html)相比,其实就是两个字符串都可以删除了,情况虽说复杂一些,但整体思路是不变的。
|
||||
|
||||
这次是两个字符串可以相互删了,这种题目也知道用动态规划的思路来解,动规五部曲,分析如下:
|
||||
@ -98,6 +100,29 @@ public:
|
||||
|
||||
```
|
||||
|
||||
### 动态规划二
|
||||
|
||||
本题和[动态规划:1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)基本相同,只要求出两个字符串的最长公共子序列长度即可,那么除了最长公共子序列之外的字符都是必须删除的,最后用两个字符串的总长度减去两个最长公共子序列的长度就是删除的最少步数。
|
||||
|
||||
代码如下:
|
||||
|
||||
```CPP
|
||||
class Solution {
|
||||
public:
|
||||
int minDistance(string word1, string word2) {
|
||||
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0));
|
||||
for (int i=1; i<=word1.size(); i++){
|
||||
for (int j=1; j<=word2.size(); j++){
|
||||
if (word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
|
||||
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
|
||||
}
|
||||
}
|
||||
return word1.size()+word2.size()-dp[word1.size()][word2.size()]*2;
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
|
@ -116,19 +116,19 @@ Java:
|
||||
```Java
|
||||
// 前序遍历·递归·LC144_二叉树的前序遍历
|
||||
class Solution {
|
||||
ArrayList<Integer> preOrderReverse(TreeNode root) {
|
||||
ArrayList<Integer> result = new ArrayList<Integer>();
|
||||
preOrder(root, result);
|
||||
public List<Integer> preorderTraversal(TreeNode root) {
|
||||
List<Integer> result = new ArrayList<Integer>();
|
||||
preorder(root, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void preOrder(TreeNode root, ArrayList<Integer> result) {
|
||||
public void preorder(TreeNode root, List<Integer> result) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
result.add(root.val); // 注意这一句
|
||||
preOrder(root.left, result);
|
||||
preOrder(root.right, result);
|
||||
result.add(root.val);
|
||||
preorder(root.left, result);
|
||||
preorder(root.right, result);
|
||||
}
|
||||
}
|
||||
// 中序遍历·递归·LC94_二叉树的中序遍历
|
||||
|
@ -67,7 +67,7 @@ deque是一个双向队列,只要封住一段,只开通另一端就可以实
|
||||
|
||||
我们也可以指定vector为栈的底层实现,初始化语句如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
|
||||
```
|
||||
|
||||
@ -77,7 +77,7 @@ std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
|
||||
|
||||
也可以指定list 为起底层实现,初始化queue的语句如下:
|
||||
|
||||
```
|
||||
```cpp
|
||||
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
|
||||
```
|
||||
|
||||
|
@ -52,7 +52,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
|
||||
```CPP
|
||||
// 先遍历物品,再遍历背包
|
||||
for(int i = 0; i < weight.size(); i++) { // 遍历物品
|
||||
for(int j = weight[i]; j < bagWeight ; j++) { // 遍历背包容量
|
||||
for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量
|
||||
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
|
||||
|
||||
}
|
||||
|
41
problems/面试题 02.07. 解法更新.md
Normal file
41
problems/面试题 02.07. 解法更新.md
Normal file
@ -0,0 +1,41 @@
|
||||
# 双指针,不计算链表长度
|
||||
设置指向headA和headB的指针pa、pb,分别遍历两个链表,每次循环同时更新pa和pb。
|
||||
* 当链表A遍历完之后,即pa为空时,将pa指向headB;
|
||||
* 当链表B遍历完之后,即pa为空时,将pb指向headA;
|
||||
* 当pa与pb相等时,即指向同一个节点,该节点即为相交起始节点。
|
||||
* 若链表不相交,则pa、pb同时为空时退出循环,即如果链表不相交,pa与pb在遍历过全部节点后同时指向结尾空节点,此时退出循环,返回空。
|
||||
# 证明思路
|
||||
设链表A不相交部分长度为a,链表B不相交部分长度为b,两个链表相交部分长度为c。<br>
|
||||
在pa指向链表A时,即pa为空之前,pa经过链表A不相交部分和相交部分,走过的长度为a+c;<br>
|
||||
pa指向链表B后,在移动相交节点之前经过链表B不相交部分,走过的长度为b,总合为a+c+b。<br>
|
||||
同理,pb走过长度的总合为b+c+a。二者相等,即pa与pb可同时到达相交起始节点。 <br>
|
||||
该方法可避免计算具体链表长度。
|
||||
```cpp
|
||||
class Solution {
|
||||
public:
|
||||
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
|
||||
//链表为空时,返回空指针
|
||||
if(headA == nullptr || headB == nullptr) return nullptr;
|
||||
ListNode* pa = headA;
|
||||
ListNode* pb = headB;
|
||||
//pa与pb在遍历过全部节点后,同时指向结尾空节点时退出循环
|
||||
while(pa != nullptr || pb != nullptr){
|
||||
//pa为空时,将pa指向headB
|
||||
if(pa == nullptr){
|
||||
pa = headB;
|
||||
}
|
||||
//pa为空时,将pb指向headA
|
||||
if(pb == nullptr){
|
||||
pb = headA;
|
||||
}
|
||||
//pa与pb相等时,返回相交起始节点
|
||||
if(pa == pb){
|
||||
return pa;
|
||||
}
|
||||
pa = pa->next;
|
||||
pb = pb->next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
```
|
Reference in New Issue
Block a user