描述:卡车有两个油箱。给你两个整数,mainTank 表示主油箱中的燃料(以升为单位),additionalTank 表示副油箱中的燃料(以升为单位)。
该卡车每耗费 1 升燃料都可以行驶 10 km。每当主油箱使用了 5 升燃料时,如果副油箱至少有 1 升燃料,则会将 1 升燃料从副油箱转移到主油箱。
返回卡车可以行驶的最大距离。
注意:从副油箱向主油箱注入燃料不是连续行为。这一事件会在每消耗 5 升燃料时突然且立即发生。
示例 1:
输入:mainTank = 5, additionalTank = 10
输出:60
解释:
在用掉 5 升燃料后,主油箱中燃料还剩下 (5 - 5 + 1) = 1 升,行驶距离为 50km 。
在用掉剩下的 1 升燃料后,没有新的燃料注入到主油箱中,主油箱变为空。
总行驶距离为 60km 。
示例 2:
输入:mainTank = 1, additionalTank = 2
输出:10
解释:
在用掉 1 升燃料后,主油箱变为空。
总行驶距离为 10km 。
提示:
1 <= mainTank, additionalTank <= 100
难度:简单。
思路:最直观的想法是,使用distance表示可以行驶的最大距离,当主油箱油量小于5时,直接返回mainTank*10,反之当主油箱油量大于等于5时,将distance加以50,再判断副油箱油量,如果副油箱油量大于等于1,则将副油箱油量减去1,同时将主油箱油量减去5再加上1,反之当副油箱油量小于1,则将主油箱油量减去5,最后退出循环后,还需要将distance加上剩余主油箱油量乘以10。
class Solution {
public:
int distanceTraveled(int mainTank, int additionalTank) {
int distance=0;
if(mainTank<5)
return mainTank*10;
while(mainTank>=5)
{
distance+=50;
//有余量
if(additionalTank>=1)
{
additionalTank-=1;
mainTank-=4;
}
//无余量
else
mainTank-=5;
}
distance+=mainTank*10;
return distance;
}
};
总结:模拟,最主要的是注意边界条件。
描述:给你一个 正 整数数组 nums 。
将 nums 分成两个数组:nums1 和 nums2 ,并满足下述条件:
数组 nums 中的每个元素都属于数组 nums1 或数组 nums2 。
两个数组都 非空 。
分区值 最小 。
分区值的计算方法是 |max(nums1) - min(nums2)| 。
其中,max(nums1) 表示数组 nums1 中的最大元素,min(nums2) 表示数组 nums2 中的最小元素。
返回表示分区值的整数。
示例 1:
输入:nums = [1,3,2,4]
输出:1
解释:可以将数组 nums 分成 nums1 = [1,2] 和 nums2 = [3,4] 。
- 数组 nums1 的最大值等于 2 。
- 数组 nums2 的最小值等于 3 。
分区值等于 |2 - 3| = 1 。
可以证明 1 是所有分区方案的最小值。
示例 2:
输入:nums = [100,1,10]
输出:9
解释:可以将数组 nums 分成 nums1 = [10] 和 nums2 = [100,1] 。
- 数组 nums1 的最大值等于 10 。
- 数组 nums2 的最小值等于 1 。
分区值等于 |10 - 1| = 9 。
可以证明 9 是所有分区方案的最小值。
提示:
2 <= nums.length <= 105
1 <= nums[i] <= 109
难度:中等。
思路:最直观的想法是,找出差值最小的两个数。首先将数组排序,然后遍历一遍求最小差值。
class Solution {
public:
int findValueOfPartition(vector& nums) {
//先排序
sort(nums.begin(),nums.end());
//再找中间两个
int n=nums.size();
int diff=INT_MAX;
for(int i=n-1;i>0;i--)
{
diff=min(diff,nums[i]-nums[i-1]);
}
return diff;
}
};
总结:有时候,题目思路很简单,但是会对题目进行很强的包装,从而产生迷惑性,故此时需要好好分析题目的本质是什么。
描述:给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数。如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列:
对于 0 <= i < n - 1 的下标 i ,要么 nums[i] % nums[i+1] == 0 ,要么 nums[i+1] % nums[i] == 0 。
请你返回特别排列的总数目,由于答案可能很大,请将它对 109 + 7 取余 后返回。
示例 1:
输入:nums = [2,3,6]
输出:2
解释:[3,6,2] 和 [2,6,3] 是 nums 两个特别的排列。
示例 2:
输入:nums = [1,4,3]
输出:2
解释:[3,1,4] 和 [4,1,3] 是 nums 两个特别的排列。
提示:
2 <= nums.length <= 14
1 <= nums[i] <= 109
难度:中等。
特别的排列:最直观的想法是,状态压缩DP+记忆化搜索。由于包含n个互不相同的整数,故此时数值下标即唯一代表数值,那么我们可以只记录下标,而不用记录具体的数值。由于是全排列,故每一个元素要么为选要么为不选,对于可选的集合,我们可以将集合映射到二进制位运算中进行计算,比如0、2、3对应数值1101。全集为(1<
const int MOD=1e9+7;
int specialPerm(vector& nums)
{
//只需要记录下标而不需要记录数字
int n=nums.size();
//将集合对应成二进制数字 left表示可选择的集合 初始为全集 1表示可选择
int left=(1< dfs=[&](int left,int i)->int
{
//递归出口 没有元素可选 即枚举完了 该排列符合
if(left==0)
return 1;
//有记录则直接返回
if(memo[left][i]!=-1)
return memo[left][i];
int ans=0;
//枚举数组下标
for(int j=0;j>j)&1判断当前位是否是1 即枚举该下标是否用过
if(((left>>j)&1)&&(nums[j]%nums[i]==0||nums[i]%nums[j]==0))
//在left中删除j并继续计算后续
ans=(ans+dfs(left^(1<
总结:注意,一般对于集合的元素选择,均可以转换为二进制位运算。