【力扣周赛】第350场周赛

【力扣周赛】第350场周赛

    • 2739. 总行驶距离
      • 题目描述
      • 解题思路
    • 2740. 找出分区值
      • 题目描述
      • 解题思路
    • 2741. 特别的排列
      • 题目描述
      • 解题思路

2739. 总行驶距离

题目描述

描述:卡车有两个油箱。给你两个整数,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;
    }
};

总结:模拟,最主要的是注意边界条件。

2740. 找出分区值

题目描述

描述:给你一个 正 整数数组 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;
    }
};

总结:有时候,题目思路很简单,但是会对题目进行很强的包装,从而产生迷惑性,故此时需要好好分析题目的本质是什么。

2741. 特别的排列

题目描述

描述:给你一个下标从 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<>i)&1。即从头到尾遍历数组,并将当前元素从可选集合中删除,然后统计在可选集合中且上一个数是i的可选方案,该统计方法即再次遍历数组,选择当前未被使用的且满足要求的元素。(整体思想回溯)

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<

总结:注意,一般对于集合的元素选择,均可以转换为二进制位运算。

你可能感兴趣的:(力扣周赛,leetcode,算法,排序算法)