二升三数学计算题300道竖式,有关时间的计算题50道
终极管理员 知识笔记 118阅读
题目要求给定一个整数数组 A我们只能用以下方法修改该数组我们选择某个索引 i 并将 A[i] 替换为 -A[i]然后总共重复这个过程 K 次。我们可以多次选择同一个索引 i。
以这种方式修改数组后返回数组可能的最大和。

示例 1
输入A [4,2,3], K 1输出5解释选择索引 (1,) 然后 A 变为 [4,-2,3]。示例 2

示例 3
输入A [2,-3,-1,5,-4], K 2输出13解释选择索引 (1, 4) 然后 A 变为 [2,3,-1,5,4]。提示
1 < A.length < 100001 < K < 10000-100 < A[i] < 100 思路贪心的思路局部最优让绝对值大的负数变为正数当前数值达到最大整体最优整个数组和达到最大。
那么如果将负数都转变为正数了K依然大于0此时的问题是一个有序正整数序列如何转变K次正负让 数组和 达到最大。
那么又是一个贪心局部最优只找数值最小的正整数进行反转当前数值和可以达到最大例如正整数数组{5, 3, 1}反转1 得到-1 比 反转5得到的-5 大多了全局最优整个 数组和 达到最大。
那么本题的解题步骤为
第一步将数组按照绝对值大小从大到小排序注意要按照绝对值的大小第二步从前向后遍历遇到负数将其变为正数同时K--第三步如果K还大于0那么反复转变数值最小的元素将K用完第四步求和class Solution {public: static bool cmp(int a, int b) { return abs(a) > abs(b); } int largestSumAfterKNegations(vector<int>& nums, int k) { sort(nums.begin(), nums.end(), cmp); for (int i 0; i < nums.size(); i) { if (nums[i] < 0 && k > 0) { nums[i] * -1; k--; } } if (k % 2 1) nums[nums.size() - 1] * -1; int res 0; for (int a : nums) res a; return res; }};
134. 加油站 题目要求在一条环路上有 N 个加油站其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发开始时油箱为空。
如果你可以绕环路行驶一周则返回出发时加油站的编号否则返回 -1。
说明:
如果题目有解该答案即为唯一答案。输入数组均为非空数组且长度相同。输入数组中的元素均为非负数。示例 1: 输入:
gas [1,2,3,4,5]cost [3,4,5,1,2]输出: 3 解释:
从 3 号加油站(索引为 3 处)出发可获得 4 升汽油。此时油箱有 0 4 4 升汽油开往 4 号加油站此时油箱有 4 - 1 5 8 升汽油开往 0 号加油站此时油箱有 8 - 2 1 7 升汽油开往 1 号加油站此时油箱有 7 - 3 2 6 升汽油开往 2 号加油站此时油箱有 6 - 4 3 5 升汽油开往 3 号加油站你需要消耗 5 升汽油正好足够你返回到 3 号加油站。因此3 可为起始索引。示例 2: 输入:
gas [2,3,4]
cost [3,4,3]
输出: -1
解释: 你不能从 0 号或 1 号加油站出发因为没有足够的汽油可以让你行驶到下一个加油站。我们从 2 号加油站出发可以获得 4 升汽油。 此时油箱有 0 4 4 升汽油。开往 0 号加油站此时油箱有 4 - 3 2 3 升汽油。开往 1 号加油站此时油箱有 3 - 3 3 3 升汽油。你无法返回 2 号加油站因为返程需要消耗 4 升汽油但是你的油箱只有 3 升汽油。因此无论怎样你都不可能绕环路行驶一周。
思路 贪心算法方法二可以换一个思路首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈说明 各个站点的加油站 剩油量rest[i]相加一定是大于等于零的。
每个加油站的剩余量rest[i]为gas[i] - cost[i]。
i从0开始累加rest[i]和记为curSum一旦curSum小于零说明[0, i]区间都不能作为起始位置因为这个区间选择任何一个位置作为起点到i这里都会断油那么起始位置从i1算起再从0计算curSum。
那么局部最优当前累加rest[i]的和curSum一旦小于0起始位置至少要是i1因为从i之前开始一定不行。全局最优找到可以跑一圈的起始位置
class Solution {public: int canCompleteCircuit(vector<int>& gas, vector<int>& cost) { int curSum 0; int totalSum 0; int start 0; for (int i 0; i < gas.size(); i) { curSum gas[i] - cost[i]; totalSum gas[i] - cost[i]; if (curSum < 0) { start i 1; curSum 0; } } if (totalSum < 0) return -1; return start; }};
时间复杂度O(n)空间复杂度O(1) 135. 分发糖果 题目要求老师想给孩子们分发糖果有 N 个孩子站成了一条直线老师会根据每个孩子的表现预先给他们评分。
你需要按照以下要求帮助老师给这些孩子分发糖果
每个孩子至少分配到 1 个糖果。相邻的孩子中评分高的孩子必须获得更多的糖果。那么这样下来老师至少需要准备多少颗糖果呢
示例 1:
输入: [1,0,2]输出: 5解释: 你可以分别给这三个孩子分发 2、1、2 颗糖果。示例 2:
输入: [1,2,2]输出: 4解释: 你可以分别给这三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果这已满足上述两个条件。 思路这道题目一定是要确定一边之后再确定另一边例如比较每一个孩子的左边然后再比较右边如果两边一起考虑一定会顾此失彼。
每一个孩子我都先给一个糖果然后都先比左边再比右边。小了的不管大了的加一。
先确定右边评分大于左边的情况也就是从前向后遍历
此时局部最优只要右边评分比左边大右边的孩子就多一个糖果全局最优相邻的孩子中评分高的右孩子获得比左边孩子更多的糖果
局部最优可以推出全局最优。
如果ratings[i] > ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个所以贪心candyVec[i] candyVec[i - 1] 1
再确定左孩子大于右孩子的情况从后向前遍历
遍历顺序这里有同学可能会有疑问为什么不能从前向后遍历呢
因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果所以 要从后向前遍历。
如果从前向后遍历rating[5]与rating[4]的比较 就不能用上 rating[5]与rating[6]的比较结果了 。如图
所以确定左孩子大于右孩子的情况一定要从后向前遍历
如果 ratings[i] > ratings[i 1]此时candyVec[i]第i个小孩的糖果数量就有两个选择了一个是candyVec[i 1] 1从右边这个加1得到的糖果数量一个是candyVec[i]之前比较右孩子大于左孩子得到的糖果数量。
那么又要贪心了局部最优取candyVec[i 1] 1 和 candyVec[i] 最大的糖果数量保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优相邻的孩子中评分高的孩子获得更多的糖果。
局部最优可以推出全局最优。
所以就取candyVec[i 1] 1 和 candyVec[i] 最大的糖果数量candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多也比右边candyVec[i 1]的糖果多。
class Solution {public: int candy(vector<int>& ratings) { vector<int> candyVec(ratings.size(), 1); // 从前向后 for (int i 1; i < ratings.size(); i) { // 右大于左 if (ratings[i] > ratings[i-1]) candyVec[i] candyVec[i-1] 1; } // 从后向前 for (int i ratings.size() - 2; i > 0; --i) { // 左大于右 if (ratings[i] > ratings[i1]) candyVec[i] max(candyVec[i], candyVec[i1] 1); } int res 0; for (int i 0; i < ratings.size(); i) res candyVec[i]; return res; }};