leetcode solution

4. Median of Two Sorted Arrays

1.原题:https://leetcode.com/problems/median-of-two-sorted-arrays/description/

2.解释:

1
2
3
4
5
6
7
8
9
对于一个长度为n的已排序数列a,若n为奇数,中位数为a[n / 2 + 1] , 
若n为偶数,则中位数(a[n / 2] + a[n / 2 + 1]) / 2
如果我们可以在两个数列中求出第K小的元素,便可以解决该问题
不妨设数列A元素个数为n,数列B元素个数为m,各自升序排序,求第k小元素
取A[k / 2] B[k / 2] 比较,
如果 A[k / 2] > B[k / 2] 那么,所求的元素必然不在B的前k / 2个元素中(证明反证法)
反之,必然不在A的前k / 2个元素中,于是我们可以将A或B数列的前k / 2元素删去,求剩下两个数列的
k - k / 2小元素,于是得到了数据规模变小的同类问题,递归解决
如果 k / 2 大于某数列个数,所求元素必然不在另一数列的前k / 2个元素中,同上操作就好。

3.代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class  {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int len1 = nums1.size();
int len2 = nums2.size();
int len = len1 + len2;
if (len & 1) {
return findkth(nums1, 0, nums2, 0, len / 2 + 1);
}
else {
return (findkth(nums1, 0, nums2, 0, len / 2) + findkth(nums1, 0, nums2, 0, len / 2 + 1)) / 2;
}
}

double findkth(vector<int>& nums1, int index1, vector<int>& nums2, int index2, int k) {
int len1 = nums1.size();
int len2 = nums2.size();
if (index1 >= len1) {
return nums2[index2 + k - 1];
}
if (index2 >= len2) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
int key1 = index1 + k / 2 - 1 >= len1 ? INT_MAX : nums1[index1 + k / 2 - 1];
int key2 = index2 + k / 2 - 1 >= len2 ? INT_MAX : nums2[index2 + k / 2 - 1];
if (key1 < key2) {
return findkth(nums1, index1 + k / 2, nums2, index2, k - k / 2);
}
else {
return findkth(nums1, index1, nums2, index2 + k / 2, k - k / 2);
}
}
};

参考链接:http://blog.csdn.net/gao1440156051/article/details/51725845

30. Substring with Concatenation of All Words

1.原题:https://leetcode.com/problems/substring-with-concatenation-of-all-words/description/

2.解释:

1
NB解法:O(n)时间复杂度,设计思路非常巧妙。这种方法不再是一个字符一个字符的遍历,而是一个词一个词的遍历,比如根据题目中的例子,字符串s的长度n为18,words数组中有两个单词(cnt=2),每个单词的长度len均为3,那么遍历的顺序为0,3,6,8,12,15,然后偏移一个字符1,4,7,9,13,16,然后再偏移一个字符2,5,8,10,14,17,这样就可以把所有情况都遍历到,我们还是先用一个哈希表m1来记录words里的所有词,然后我们从0开始遍历,用left来记录左边界的位置,count表示当前已经匹配的单词的个数。然后我们一个单词一个单词的遍历,如果当前遍历的到的单词t在m1中存在,那么我们将其加入另一个哈希表m2中,如果在m2中个数小于等于m1中的个数,那么我们count自增1,如果大于了,那么需要做一些处理,比如下面这种情况, s = barfoofoo, words = {bar, foo, abc}, 我们给words中新加了一个abc,目的是为了遍历到barfoo不会停止,那么当遍历到第二foo的时候, m2[foo]=2, 而此时m1[foo]=1,这是后已经不连续了,所以我们要移动左边界left的位置,我们先把第一个词t1=bar取出来,然后将m2[t1]自减1,如果此时m2[t1]<m1[t1]了,说明一个匹配没了,那么对应的count也要自减1,然后左边界加上个len,这样就可以了。如果某个时刻count和cnt相等了,说明我们成功匹配了一个位置,那么将当前左边界left存入结果res中,此时去掉最左边的一个词,同时count自减1,左边界右移len,继续匹配。如果我们匹配到一个不在m1中的词,那么说明跟前面已经断开了,我们重置m2,count为0,左边界left移到j+len。

3.代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class  {
public:
vector<int> findSubstring(string s, vector<string>& words) {

vector<int> res;
int slen = s.length();
int wlen = words.size();
if (slen <= 0 || wlen <= 0)
return res;
int word_len = words[0].length();
if (word_len == 0) {
for (int i = 0; i <= slen; i++)
res.push_back(i);
return res;
}
unordered_map<string, int> dict;
for (int i = 0; i < wlen; i++)
dict[words[i]]++;

for (int i = 0; i < word_len; i++) {
unordered_map<string, int> move_dict;
int left = i, count = 0;
for (int j = i; j <= slen - word_len; j += word_len) {
string str = s.substr(j, word_len);
if (dict.count(str)) {
move_dict[str]++;
if (move_dict[str] <= dict[str])
count++;
else {
while (move_dict[str] > dict[str]) {
string temp = s.substr(left, word_len);
move_dict[temp]--;
if (move_dict[temp] < dict[temp])
count--;
left += word_len;
}
}
if (count == wlen) {
res.push_back(left);
move_dict[s.substr(left, word_len)]--;
count--;
left += word_len;
}
}
else {
move_dict.clear();
count = 0;
left = j + word_len;
}
}
}
return res;
}
};

参考链接:

https://www.cnblogs.com/grandyang/p/4521224.html

https://leetcode.com/problems/substring-with-concatenation-of-all-words/discuss/13656/An-O(N)-solution-with-detailed-explanation

#回溯问题

1.相关问题:子集,组合和,排列,回文分区(Subsets, Permutations, Combination Sum, Palindrome Partitioning)等

扫描二维码关注公众号,回复: 7397190 查看本文章

2.子集Subsets(https://leetcode.com/problems/subsets/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}

private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}

3.子集II(包含重复项)(https://leetcode.com/problems/subsets-ii/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class  {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int> > list;
vector<bool> used(nums.size(), false);
sort(nums.begin(), nums.end());
backtrack(list, vector<int>(), nums, used, 0);
return list;
}

void backtrack(vector<vector<int>>& list , vector<int> tempList, vector<int>& nums, vector<bool> used, int start){
list.push_back(tempList);
for(int i = start; i < nums.size(); i++){
if (i > start && used[i - 1] == false && nums[i] == nums[i - 1])
continue;
tempList.push_back(nums[i]);
used[i] = true;
backtrack(list, tempList, nums, used, i + 1);
tempList.pop_back();
used[i] = false;
}
}
};

4.组合总和(https://leetcode.com/problems/combination-sum/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class  {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
if (candidates.size() == 0)
return res;
sort(candidates.begin(), candidates.end());
if (target < candidates[0])
return res;
vector<int> combination;
backTrack(res, candidates, combination, target, 0);
return res;
}

private:
void backTrack(vector<vector<int>>& res, vector<int> candidates, vector<int> combination, int target, int begin) {
if (target < 0)
return;
else if (target == 0) {
res.push_back(combination);
return;
}
for (int i = begin; i < candidates.size() && target >= candidates[i]; i++) {
combination.push_back(candidates[i]);
backTrack(res, candidates, combination, target - candidates[i], i);
combination.pop_back();
}
}
};

5.组合总和II(不能重复使用相同的元素)(https://leetcode.com/problems/combination-sum-ii/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class  {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
if (candidates.size() == 0)
return res;
sort(candidates.begin(), candidates.end());
if (target < candidates[0])
return res;
vector<int> combination;
backTrack(res, candidates, combination, target, 0);
return res;
}

private:
void backTrack(vector<vector<int>>& res, vector<int> candidates, vector<int> combination, int target, int begin) {
if (target < 0)
return;
else if (target == 0) {
res.push_back(combination);
return;
}
for (int i = begin; i < candidates.size() && target >= candidates[i]; i++) {
if (i == begin || candidates[i] != candidates[i - 1]) {
combination.push_back(candidates[i]);
backTrack(res, candidates, combination, target - candidates[i], i + 1);
combination.pop_back();
}
}
}
};

6.组合总和III(不能重复使用相同的元素)(https://leetcode.com/problems/combination-sum-iii/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
std::vector<std::vector<int> > combinationSum3(int k, int n) {
std::vector<std::vector<int> > res;
std::vector<int> combination;
combinationSum3(n, res, combination, 1, k);
return res;
}
private:
void combinationSum3(int target, std::vector<std::vector<int> > &res, std::vector<int> &combination, int begin, int need) {
if (!target) {
res.push_back(combination);
return;
}
else if (!need)
return;
for (int i = begin; i != 10 && target >= i * need + need * (need - 1) / 2; ++i) {
combination.push_back(i);
combinationSum3(target - i, res, combination, i + 1, need - 1);
combination.pop_back();
}
}
};

7.排列组合(https://leetcode.com/problems/permutations/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
// Arrays.sort(nums); // not necessary
backtrack(list, new ArrayList<>(), nums);
return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(tempList.contains(nums[i])) continue; // element already exists, skip
tempList.add(nums[i]);
backtrack(list, tempList, nums);
tempList.remove(tempList.size() - 1);
}
}
}

8.排列II(包含重复项)(https://leetcode.com/problems/permutations-ii/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
return list;
}

private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, boolean [] used){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
used[i] = true;
tempList.add(nums[i]);
backtrack(list, tempList, nums, used);
used[i] = false;
tempList.remove(tempList.size() - 1);
}
}
}

9.回文分区(https://leetcode.com/problems/palindrome-partitioning/):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public List<List<String>> partition(String s) {
List<List<String>> list = new ArrayList<>();
backtrack(list, new ArrayList<>(), s, 0);
return list;
}

public void backtrack(List<List<String>> list, List<String> tempList, String s, int start){
if(start == s.length())
list.add(new ArrayList<>(tempList));
else{
for(int i = start; i < s.length(); i++){
if(isPalindrome(s, start, i)){
tempList.add(s.substring(start, i + 1));
backtrack(list, tempList, s, i + 1);
tempList.remove(tempList.size() - 1);
}
}
}
}

public boolean isPalindrome(String s, int low, int high){
while(low < high)
if(s.charAt(low++) != s.charAt(high--)) return false;
return true;
}

参考链接:

https://leetcode.com/problems/combination-sum/discuss/16502/A-general-approach-to-backtracking-questions-in-Java-(Subsets-Permutations-Combination-Sum-Palindrome-Partitioning)

https://leetcode.com/problems/combination-sum/discuss/16496/Accepted-16ms-c++-solution-use-backtracking-easy-understand.

42. Trapping Rain Water

1.原题:https://leetcode.com/problems/trapping-rain-water/description/

2.解法一(DP):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int trap(vector<int>& height)
{
if(height == null)
return 0;
int ans = 0;
int size = height.size();
vector<int> left_max(size), right_max(size);
left_max[0] = height[0];
for (int i = 1; i < size; i++) {
left_max[i] = max(height[i], left_max[i - 1]);
}
right_max[size - 1] = height[size - 1];
for (int i = size - 2; i >= 0; i--) {
right_max[i] = max(height[i], right_max[i + 1]);
}
for (int i = 1; i < size - 1; i++) {
ans += min(left_max[i], right_max[i]) - height[i];
}
return ans;
}

3.解法二(双指针):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int trap(int A[], int n) {
int left=0; int right=n-1;
int res=0;
int maxleft=0, maxright=0;
while(left<=right){
if(A[left]<=A[right]){
if(A[left]>=maxleft) maxleft=A[left];
else res+=maxleft-A[left];
left++;
}
else{
if(A[right]>=maxright) maxright= A[right];
else res+=maxright-A[right];
right--;
}
}
return res;
}
};

参考链接:

https://leetcode.com/problems/trapping-rain-water/solution/

https://leetcode.com/problems/trapping-rain-water/discuss/17357/Sharing-my-simple-c++-code:-O(n)-time-O(1)-space

原文:大专栏  leetcode solution


猜你喜欢

转载自www.cnblogs.com/petewell/p/11611756.html
今日推荐