3. Longest Substring Without Repeating Characters
思路:假设s[i,j-1]是没有重复字符的子串,那么这个时候只需要s[j]没有在s[i,j-1]中出现过即可,所以可以引入hash表。这里还是用双指针一个记录子串开头,一个记录子串结尾。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//时间复杂度O(2n),空间复杂度O(min(m,n))
if (s.empty()) return 0;
unordered_set <int> set;
int len = INT_MIN;
int i = 0, j = 0;
while (i < s.size() && j < s.size()) {
if (!set.count(s[j])) {
set.insert(s[j++]);
len = max(len, j-i);
}
else
set.erase(s[i++]);
}
return len;
}
};
上面每次遇到重复字符的时候,i就开始向后移动一直移到没有重复字符的地方,所以可以考虑用hash_map记录字符和位置,然后直接移到没有重复字符的位置,而不是累加。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
//时间复杂度O(n),空间复杂度O(min(m,n))
if (s.empty()) return 0;
unordered_map <char, int> map;
int len = INT_MIN;
int i = 0, j = 0;
while (i < s.size() && j < s.size()) {
if (map.find(s[j]) != map.end())
i = max(map[s[j]],i);
len = max(len, j - i + 1);
map[s[j]] = j + 1;
++j;
}
return len == INT_MIN ? 0 : len;
}
};
11. Container With Most Water
Given n non-negative integers a1, a2, …, an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
思路:双指针法,短的一边会引起水量减少,设置两个点,一个从开头,一个从结尾,比较两边,把短的一边向中间靠拢。
class Solution {
public:
int maxArea(vector<int>& height) {
if (height.empty() || height.size() == 1)
return 0;
int start = 0, end = height.size() - 1;
int water = 0;
while (start < end) {
while (height[start] == 0) ++start;
while (height[end] == 0) --end;
water = max(water, (end - start) * min(height[end], height[start]));
if (height[start] < height[end]) ++start;
else --end;
}
return water;
}
};
26. Remove Duplicates from Sorted Array
给定一个有序数组,移除其中的重复元素,保证每个数字只出现过一次,返回移除后的数组长度。
思路:两个指针,一个遍历,一个记录重复元素个数,注意如果要AC必须修改原数组。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int cnt = 0;
if (nums.empty()) return cnt;
for (int i = 1; i < nums.size(); ++i) {
if (nums[i] == nums[i-1]) cnt++;
else nums[i-cnt] = nums[i];
}
return nums.size() - cnt;
}
};
209. Minimum Size Subarray Sum
双指针:
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int numsLen = nums.size();
int minLen = numsLen + 1;
int j = 0, sum = 0;
for (int i = 0; i < numsLen; ++i) {
while (sum < s && j < numsLen) {
sum += nums[j];
j++;
}
if (sum < s) break;//防止和不够的时候
minLen = min(minLen, j - i);//j-i不用+1
sum -= nums[i];
}
return minLen == numsLen + 1 ? 0 : minLen;
}
};
30. Substring with Concatenation of All Words
题目:给定一个长字符串,再给定几个长度相同的单词,让我们找出串联给定所有单词的子串的起始位置
思路一:用两个哈希表,一个哈希表先把所有的单词存进去,然后从字符串开头开始一个个字符遍历,每次找出给定单词长度的子串,看其是否在第一个哈希表里,如果没有,则break,如果有,则加入第二个哈希表,但相同的词只能出现一次,所以比较两个hash表中子串出现的次数如果多了,也break。如果正好匹配完给定单词集里所有的单词,则把i存入结果中。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
vector<int> res;
if (words.empty() || s.empty() || s.size() < words.size()) return res;
unordered_map <string, int> hash_words;
for (int i = 0; i < words.size(); ++i) {
++hash_words[words[i]];
}
int wNum = words.size(), wSize = words[0].size();
// int m = (int)s.size() - wNum*wSize;
for (int i = 0; i <= (int)s.size() - wNum*wSize; ++i) {
unordered_map<string, int> hash_string;
int j;//j记录第几个单词
for(j = 0; j < wNum; ++j) {
string tmp = s.substr(i + wSize * j, wSize);
if (hash_words.find(tmp) == hash_words.end())
break;
++hash_string[tmp];
if (hash_string[tmp] > hash_words[tmp])
break;
}
if (j == wNum) res.push_back(i);
}
return res;
}
};
思路二: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,如果大于了,说明后面已经不连续了,所以我们要移动左边界left的位置,我们先把第一个词t1=bar取出来,然后将m2[t1]自减1,如果此时m2[t1]
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (s.empty() || words.empty()) return {};
vector<int> res;
int n = s.size(), cnt = words.size(), len = words[0].size();
unordered_map<string, int> m1;
for (string w : words) ++m1[w];
for (int i = 0; i < len; ++i) {
int left = i, count = 0;
unordered_map<string, int> m2;
for (int j = i; j <= n - len; j += len) {
string t = s.substr(j, len);
if (m1.count(t)) {
++m2[t];
if (m2[t] <= m1[t]) {
++count;
} else {
while (m2[t] > m1[t]) {
string t1 = s.substr(left, len);
--m2[t1];
if (m2[t1] < m1[t1]) --count;
left += len;
}
}
if (count == cnt) {
res.push_back(left);
--m2[s.substr(left, len)];
--count;
left += len;
}
} else {
m2.clear();
count = 0;
left = j + len;
}
}
}
return res;
}
};
参考资料:http://www.cnblogs.com/grandyang/p/4521224.html
33. Search in Rotated Sorted Array
题目:在旋转的有序数组中查找,如果查找失败,返回-1;
(i.e., 0 1 2 4 5 6 7 旋转为 4 5 6 7 0 1 2).
思路:先找到最小数,然后接着查找,主要是二分
class Solution {
public:
int partition(vector<int>& nums, int target, int i, int j) {
if (i == j) return nums[i] == target ? i : -1;
if (nums[j] < target || nums[i] > target || i > j) return -1;
while (j >= i) {
int mid = (i + j) / 2;
if (nums[mid] > target)
j = mid - 1;
else if (nums[mid] < target)
i = mid + 1;
else
return mid;
}
return -1;
}
int search(vector<int>& nums, int target) {
if (nums.empty()) return -1;
int i = 0;
int j = nums.size() - 1;
//注意只有一个元素的情况
if (i == j) return nums[i] == target ? 0 : -1;
int mid = i;
while (nums[i] >= nums[j]) {
if (j - i == 1)
{
mid = j;
break;
}
mid = (i + j) / 2;
if (nums[mid] >= nums[i])
i = mid;
else if (nums[mid] <= nums[j])
j = mid;
}
if (mid == 0) return partition(nums, target, 0, nums.size()-1);
int prev = partition(nums, target, 0, mid-1);
int end = partition(nums, target, mid, nums.size()-1);
return prev == -1 ? end : prev;
}
};
别人的代码,优雅版:
class Solution {
public:
int search(int A[], int n, int target) {
int lo=0,hi=n-1;
// find the index of the smallest value using binary search.
// Loop will terminate since mid < hi, and lo or hi will shrink by at least 1.
// Proof by contradiction that mid < hi: if mid==hi, then lo==hi and loop would have been terminated.
while(lo<hi){
int mid=(lo+hi)/2;
if(A[mid]>A[hi]) lo=mid+1;
else hi=mid;
}
// lo==hi is the index of the smallest value and also the number of places rotated.
int rot=lo;
lo=0;hi=n-1;
// The usual binary search and accounting for rotation.
while(lo<=hi){
int mid=(lo+hi)/2;
//偏移的角度去理解
int realmid=(mid+rot)%n;
if(A[realmid]==target)return realmid;
if(A[realmid]<target)lo=mid+1;
else hi=mid-1;
}
return -1;
}
};
另外思路:每次在部分有序的数组中进行查找
public class Solution {
public int search(int[] A, int target) {
int lo = 0;
int hi = A.length - 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (A[mid] == target) return mid;
//mid前面有序
if (A[lo] <= A[mid]) {
if (target >= A[lo] && target < A[mid]) {
hi = mid - 1;
} else {
lo = mid + 1;
}
}//mid后面有序
else {
if (target > A[mid] && target <= A[hi]) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
}
return A[lo] == target ? lo : -1;
}