- 子数组最大的和
受到昨天最后一题的启发,第一反应就是维护一个全局最大值和一个局部最大值。那么为题就是什么时候更新局部最大值,什么时候更新全局最大值呢?最开始的想法是,如果nums[i]<0就不把nums[i]算进局部最大值,但是很容易发现这种思路不对。
于是后面想到正确的判断条件是,如果局部最大值小于0,我们就更新将现在的元素初始化新的局部最大值。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int i=1,g_max=nums[0],l_max=nums[0];
for(;i<nums.size();i++)
{
if(l_max<0)
l_max = nums[i];
else
{
l_max += nums[i];
}
g_max = max(g_max, l_max);
}
return g_max;
}
};
- 划分字母区间
思路很简单,利用双指针,一个从前往后,一个从后往前。如果二者相同,则找到某个最小区间的子集。接着,遍历这个子集内的所有元素是否在后指针之后,在的话更新子集的右区间为它的索引。
为了使得速度更快一点,考虑遍历的过程中如果遇到之前已经访问过的元素,则直接跳过。由于元素是由26个小写字母组成,所以,可以通过维护一个size为26的vector来记录某个元素是否访问过(试验证明能减少50%的时间)。
class Solution { //10:07-10:51 记录一下做题时间,能让自己在做题的时候有一种紧迫感
public:
vector<int> partitionLabels(string S) {
int l=0,r=S.size()-1, loc_r,ol;
vector<int> read(26,0), read2(26,0), ans;
while(vec_sum(ans) != S.size())
{
ol = l;
read[S[l]-'a']=1;
while(S[r] != S[l])
{
r--;
}
while(l<r)
{
l++;
if(read[S[l]-'a'])
continue;
else
{
loc_r = S.size()-1;
while(S[loc_r] != S[l] && loc_r>r)
{
loc_r--;
}
read[S[l]-'a']=1;
r=loc_r;
}
}
ans.push_back(r-ol+1);
read = read2;
r=S.size()-1;
l++;
}
return ans;
}
int vec_sum(vector<int>& v)
{
int sum=0;
for(int& x:v)
sum += x;
return sum;
}
};
看了答案,有利用字典的方法。字典的key就是s中的没个元素,value是该元素对应的最后一个索引。我记得剑指offer上有道题目,为了找到某个位置,书上给的方法是for loop遍历,LeetCode上也有答案想到了用字典代替遍历。
但是字典其实会占据比较大的空间。官方解答中,用26个长度的向量代替了字典。
class Solution { //10:07-10:51
public:
vector<int> partitionLabels(string S) {
vector<int> result;
unordered_map<char, int> map; //记录char c 和其最后出现位置的 map
int start = 0, end = 0;
for (int i = 0; i < S.size(); i ++) {
map[S[i]] = i;
}
for (int i = 0; i < S.size(); i ++) {
end = max(end, map[S[i]]);
if (i == end) {
result.push_back(end - start + 1);
start = i + 1;
}
}
return result;
}
};
接下来是二分查找的内容
3. 开方
class Solution {
public:
int mySqrt(int x) {
if(x==0) //要单独考虑x==0的情况是为了避免mid=0,并且被作为除数
return 0;
int l=1,r=x;
int mid;
while(l<r)
{
mid = (r / 2 + l / 2);
// 为了避免溢出
if(mid == x / mid || (mid < x / mid && (mid + 1) > x / (mid + 1)))
return mid;
else if(mid < x / mid)
l = mid+1;
else
r = mid-1;
}
return l;
}
};
法2:取对数
class Solution {
public:
int mySqrt(int x) {
if (x == 0) {
return 0;
}
int ans = exp(0.5 * log(x)); //C++中的
return ((long long)(ans + 1) * (ans + 1) <= x ? ans + 1 : ans);
}
};
class Solution { //15:59 - 16:27 第2次提交通过
public:
char nextGreatestLetter(vector<char>& letters, char target) {
int l=0, r=letters.size()-1;
while(l<r)
{
int m = l + (r - l) / 2;
if(letters[m] <= target)
l = m + 1;
else
r = m - 1;
}
if(l<letters.size()-1)
return letters[l] <= target ? letters[l+1] : letters[l];
else
return letters[l] <= target ? letters[0] : letters[l];
}
};
- 找出单一元素
剑指offer原题。
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int ans = 0; //任何数异或0都为它本身。任何数任何它本身都为0.
for(int &x : nums)
ans ^= x;
return ans;
}
};
打脸了,题目要求O(logn)时间复杂度,显然位运算不对。改为二分:
class Solution { //17:25 - 18:54
public:
int singleNonDuplicate(vector<int>& nums) {
int l=0,r=nums.size()-1;
int mid;
while(l<r)
{
mid = l + (r-l)/2;
if(mid == 0)
return nums[0];
//else if(mid == 1)
// return nums[1] == nums[0] ? nums[2] : nums[0];
else if(nums[mid-1]!=nums[mid] && (nums[mid+1]!=nums[mid]))
return nums[mid];
else if(nums[mid-1]==nums[mid] && ((mid-l+1) % 2 == 1))
{
r = mid - 2;
}
else if(nums[mid-1]==nums[mid] && ((mid-l+1) % 2 == 0))
{
l = mid + 1;
}
else if(nums[mid-1]!=nums[mid] && ((mid-l+1) % 2 == 1))
{
l = mid + 2;
}
else
{
r = mid - 1;
}
}
return nums[l];
}
};