给你一个由若干 0 和 1 组成的字符串 s ,请你计算并返回将该字符串分割成两个 非空 子字符串(即 左 子字符串和 右 子字符串)所能获得的最大得分。
「分割字符串的得分」为 左 子字符串中 0 的数量加上 右 子字符串中 1 的数量。
示例 1:
输入:s = "011101"
输出:5
解释:
将字符串 s 划分为两个非空子字符串的可行方案有:
左子字符串 = "0" 且 右子字符串 = "11101",得分 = 1 + 4 = 5
左子字符串 = "01" 且 右子字符串 = "1101",得分 = 1 + 3 = 4
左子字符串 = "011" 且 右子字符串 = "101",得分 = 1 + 2 = 3
左子字符串 = "0111" 且 右子字符串 = "01",得分 = 1 + 1 = 2
左子字符串 = "01110" 且 右子字符串 = "1",得分 = 2 + 1 = 3
示例 2:
输入:s = "00111"
输出:5
解释:当 左子字符串 = "00" 且 右子字符串 = "111" 时,我们得到最大得分 = 2 + 3 = 5
示例 3:
输入:s = "1111"
输出:3
提示:
2 <= s.length <= 500
字符串 s 仅由字符 '0' 和 '1' 组成。
用 iterator 迭代器 指向字符串的第二个字符位置,并逐渐向后遍历,每次用 count 函数统计iterator 前面 0 的个数 和 后面 1 的个数 ,并求和 ,找到求和最大值即可。
class Solution {
public:
int maxScore(string s) {
if(s.size() == 0 or s.size() == 1)
return 0;
string::iterator iter = s.begin() + 1;
int maxnum = 0;
for(; iter != s.end(); iter++)
{
int tempnum = count(s.begin(), iter, '0') + count(iter, s.end(), '1');
if(maxnum < tempnum)
maxnum = tempnum;
}
return maxnum;
}
};
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints
给出。每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k
张卡牌。你的点数就是你拿到手中的所有卡牌的点数之和。给你一个整数数组cardPoints
和整数k
,请你返回可以获得的最大点数
示例 1:
输入:cardPoints = [1,2,3,4,5,6,1], k = 3
输出:12
解释:第一次行动,不管拿哪张牌,你的点数总是 1 。
但是,先拿最右边的卡牌将会最大化你的可获得点数。
最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12 。
示例 2:
输入:cardPoints = [2,2,2], k = 2
输出:4
解释:无论你拿起哪两张卡牌,可获得的点数总是 4 。
示例 3:
输入:cardPoints = [9,7,7,9,7,7,9], k = 7
输出:55
解释:你必须拿起所有卡牌,可以获得的点数为所有卡牌的点数之和。
示例 4:
输入:cardPoints = [1,1000,1], k = 1
输出:1
解释:你无法拿到中间那张卡牌,所以可以获得的最大点数为 1 。
示例 5:
输入:cardPoints = [1,79,80,1,1,1,200,1], k = 3
输出:202
提示:
1 <= cardPoints.length <= 10^5
1 <= cardPoints[i] <= 10^4
1 <= k <= cardPoints.length
方法是由很多种的,有的解法是会超时的。
class Solution {
public:
int maxScore(vector<int>& cardPoints, int k) {
int sum = accumulate(cardPoints.begin(), cardPoints.end(), 0);
int min = INT_MAX, minsum = 0;
int len = cardPoints.size() - k;
for(int i = 0; i < cardPoints.size(); i++)
{
minsum += cardPoints[i];
if(i >= len) // 保证滑动窗口每次都是 len 个元素
minsum -= cardPoints[i - len];
if(i >= len - 1) // 求滑动窗口中元素和的最小值
min = minsum < min ? minsum : min;
}
return sum - min;
}
}
给你一个列表 nums ,里面每一个元素都是一个整数列表。请你依照下面各图的规则,按顺序返回 nums 中对角线上的整数。
输入:nums = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,4,2,7,5,3,8,6,9]
示例 2:
输入:nums = [[1,2,3,4,5],[6,7],[8],[9,10,11],[12,13,14,15,16]]
输出:[1,6,2,8,7,3,9,4,12,10,5,13,11,14,15,16]
示例 3:
输入:nums = [[1,2,3],[4],[5,6,7],[8],[9,10,11]]
输出:[1,4,2,5,3,8,6,9,7,10,11]
示例 4:
输入:nums = [[1,2,3,4,5,6]]
输出:[1,2,3,4,5,6]
提示:
1 <= nums.length <= 10^5
1 <= nums[i].length <= 10^5
1 <= nums[i][j] <= 10^9
nums 中最多有 10^5 个数字。
通过观察可以发现,对角线上的元素数组下标之和是固定的。可以使用将nums[i][j]
(i + j 之和相同)赋给同一个vector
,但是注意遍历整个vector
时,要从后向前遍历,省去了逆置的环节。
使用容器map的特性求解,map
语法的使用:
map<key, value> imap;
imap[key] = value;
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& nums) {
vector<int> ivec;
map<int, vector<int>> imap; // key 是数组下标 value 是vector容器
for(int i = nums.size() - 1; i >= 0; i--)
for(int j = 0; j < nums[i].size(); j++)
imap[i + j].push_back(nums[i][j]); // 可以将对角线元素存储到同一个vector中,即i + j 之和相同的元素 存入相同的vector中
for(auto& i : imap) //加上引用 防止数值的再次复制 提高程序效率
for(auto& num : i.second)
ivec.push_back(num); // 依次遍历map中的元素即可
return ivec;
}
};
给你一个整数数组 nums
和一个整数k
,请你返回 非空 子序列元素和的最大值,子序列需要满足:子序列中每两个 相邻 的整数 nums[i]
和 nums[j]
,它们在原数组中的下标 i
和 j
满足i < j
且j - i <= k
。
数组的子序列定义为:将数组中的若干个数字删除(可以删除0 个数字),剩下的数字按照原本的顺序排布。
示例 1:
输入:nums = [10,2,-10,5,20], k = 2
输出:37
解释:子序列为 [10, 2, 5, 20] 。
示例 2:
输入:nums = [-1,-2,-3], k = 1
输出:-1
解释:子序列必须是非空的,所以我们选择最大的数字。
示例 3:
输入:nums = [10,-2,-10,-5,20], k = 2
输出:23
解释:子序列为 [10, -2, -5, 20] 。
提示:
1 <= k <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
class Solution {
public:
int constrainedSubsetSum(vector<int>& nums, int k) {
vector<int> ivec(nums.size(), 0);
deque<int> ide;
ivec[0] = nums[0];
ide.push_back(0);
int maxnum = nums[0];
for(int i = 1; i < nums.size(); i++)
{
ivec[i] = max(ivec[ide.front()] + nums[i], nums[i]);
maxnum = max(maxnum, ivec[i]);
if(i - ide.front() == k)
ide.pop_front();
while(ide.size() and ivec[ide.back()] < ivec[i])
ide.pop_back();
ide.push_back(i);
}
return maxnum;
}
};
count()
函数计数即可。