当前位置: 首页 > news >正文

Leetcode 6207 -- DP | 思维 | 双指针

题目描述

max min

思路

思维本质上就是一个优化的双指针,所以这里只分析双指针。
我们可以把原数组看作由被不在[minx,maxn]范围内的数分隔的多个子数组,那么问题就转换成了如何在一个子数组中不重不漏的找出所有满足要求的字数组。
方法很简单,枚举右断点就可以了。然后,如果我们希望我们的子数组的个数尽可能的多,那么左端点应该尽可能靠近右断点。

dp的思路真的太妙了,第一次看见这种思路。

思维代码

class Solution {
    func countSubarrays(_ nums: [Int], _ minK: Int, _ maxK: Int) -> Int {
        let segments = nums.split { $0 > maxK || $0 < minK}
        var ans = 0
        for s in segments {
            let seg = [Int](s)
            guard seg.contains(minK) && seg.contains(maxK) else {continue}
            let N = seg.count
            var latestMinKIdx = -1
            var latestMaxKIdx = -1

            for i in 0..<N {
                if seg[i] == minK {
                    latestMinKIdx = i
                }
                if seg[i] == maxK {
                    latestMaxKIdx = i
                }
                let necessaryIdx = min(latestMinKIdx, latestMaxKIdx)
                if necessaryIdx != -1 {
                    ans += necessaryIdx + 1
                }
            }
        }
        return ans
    }
}

class Solution {
    func countSubarrays(_ nums: [Int], _ minK: Int, _ maxK: Int) -> Int {
        var ans = 0
        var left = -1
        var latestMinKIdx = -1
        var latestMaxKIdx = -1
        let N = nums.count
        for i in 0..<N {
            if nums[i] == minK {
                latestMinKIdx = i
            }
            if nums[i] == maxK {
                latestMaxKIdx = i
            }
            if nums[i] >= minK && nums[i] <= maxK {
                let necessaryIdx = min(latestMinKIdx, latestMaxKIdx)
                if necessaryIdx != -1 {
                    ans += necessaryIdx - left
                }
            } else {
                latestMaxKIdx = -1
                latestMinKIdx = -1
                left = i
            }
        }
        return ans
    }
}

作者:RobinLiu
链接:https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/solution/by-robinliu-0x9r/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

dp代码

class Solution {
public:
    long long countSubarrays(vector<int>& nums, int minx, int maxn) {
        /*
        以条件A表示最大值为maxn,条件B表示最小值为minx,设置dp[nums.length][4]数组
        dp[i][0/1/2/3]分别表示分别满足下面条件的子数组的个数:
            [0]: 以nums[i]为结尾的子数组中满足条件A&&B的, maxn, minx
            [1]: 只满足条件A的, maxn
            [2]: 只满足条件B的, minx
            [3]: 两个条件都不满足但没有超出[minx,maxn]范围的, null
        再一次遍历每次根据nums[i]和dp[i-1]确定dp[i]
        */
        int n = nums.size();
        long long res = 0;
        vector<vector<long long>> dp(n, vector<long long>(4));
        // 由于 nums[0] 前面没有元素无法dp,所以预处理nums[0]
        if(nums[0] == maxn && nums[0] == minx)  dp[0][0] = 1;
        else if(nums[0] == maxn)    dp[0][1] = 1;
        else if(nums[0] == minx)    dp[0][2] = 1;
        else if(nums[0] >= minx && nums[0] <= maxn) dp[0][3] = 1;
        res += dp[0][0];
        
        for(int i = 1; i < n; i ++ )
        {
            if(nums[i] == maxn && nums[i] == minx)  
            {
                dp[i][0] = 1 + dp[i - 1][0] + dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3];
            }
            else if(nums[i] == maxn)   
            {
                dp[i][1] = 1 + dp[i - 1][1] + dp[i - 1][3];
                dp[i][0] = dp[i - 1][2] + dp[i - 1][0];
            }
            else if(nums[i] == minx)
            {
                dp[i][2] = 1 + dp[i - 1][2] + dp[i - 1][3];
                dp[i][0] = dp[i - 1][0] + dp[i - 1][1];
            }
            else if(nums[i] >= minx && nums[i] <= maxn)
            {
                dp[i][0] = dp[i - 1][0];
                dp[i][1] = dp[i - 1][1];
                dp[i][2] = dp[i - 1][2];
                dp[i][3] = 1 + dp[i - 1][3];
            }
            res += dp[i][0];
        }
        return res;
    }
};

双指针代码

class Solution {
public:
    long long countSubarrays(vector<int>& nums, int minx, int maxn) {
        int n = nums.size();
        long long res = 0;
        int smin = 0, smax = 0; // count of maxn and minx
        // i就是我们的右端点,j是最靠近i的左端点,last 是最左侧那个没有超出范围的数的位置
        // [j,i] 这个范围时我们必须包含的
        // [last,j-1] 这个范围内的数我们是可选可不选的,一共有 j-1-last+1=j-last 种方案
        // 但是别忘了,我们也可以一个都不选,这也是一种方案
        // 所有一共有 j-last+1 种方案
        for(int i = 0, last = 0, j = 0; i < n; i ++ ) 
        {
            if(nums[i] < minx || nums[i] > maxn)    
            {
                // 如果当前数不在范围,更新状态
                j = last = i + 1; // 因为 j 和 last 都必须在范围内,所以最近也得是下一个数才符合条件
                smin = smax = 0;
                continue;
            }
            
            // minx mightly equal maxn
            if(nums[i] == minx) smin ++ ;
            if(nums[i] == maxn) smax ++ ;
            
            while(j <= i)
            {
                if(nums[j] == minx) smin -- ;
                if(nums[j] == maxn) smax -- ;
                if(!smin || !smax) // 回溯,当前j已经是最靠右的位置,在往右走不满足条件了
                {
                    if(nums[j] == minx) smin ++ ;
                    if(nums[j] == maxn) smax ++ ;
                    break;
                }
                j ++ ;
            }
            
            if(smin && smax)    res += j - last + 1;
        }
        
        return res;
    }
};


## 借鉴
[思维](https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/solution/jian-ji-xie-fa-pythonjavacgo-by-endlessc-gag2/)

[dp,太牛了](https://leetcode.cn/problems/count-subarrays-with-fixed-bounds/solution/dpyi-ci-bian-li-by-confident-galileoxn2-tto7/)

[codeforce](https://codeforces.com/problemset/problem/1730/E)
http://www.dtcms.com/a/107284.html

相关文章:

  • catch-all路由
  • 数据结构初阶: 顺序表的增删查改
  • 【LeetCode Solutions】LeetCode 126 ~ 130 题解
  • Selenium自动化中的 三大时间等待
  • gcc 链接顺序,静态库循环依赖问题
  • 「青牛科技」GC5849 12V三相无感正弦波电机驱动芯片
  • RISC-V debug专栏2 --- Debug Module(DM)
  • 在将asc文件导入maxent文件时出现for input string:“nan“
  • (kotlin) Android 13 高版本 图片选择、显示与裁剪功能实现
  • Docker容器部署Java项目的自动化脚本(Shell编写)
  • 动态规划练习题①
  • 蓝桥杯 web 灯的颜色变化(Dom操作及样式动态修改、浏览器解析顺序、定时器)
  • 计算机科学基础设施之数学:科研工具、资源与环境详介
  • qt.qpa.xcb: could not connect to display解决方法
  • Keil5烧录后STM32不自动运行?必须复位才能启动的终极解决方案
  • element-plus中,Upload上传组件的使用 + 后端处理
  • DMA在SPI和I2C通信中的应用详解
  • 解锁异步编程新姿势:CompletableFuture 深度探秘
  • java根据集合中对象的属性值大小生成排名
  • [NOIP 1999 提高组] 导弹拦截
  • C++ STL简单的几个容器
  • I²C总线高级特性与故障处理分析
  • 【leetcode100】每日温度
  • OpenCV 从入门到精通(day_04)
  • 面向对象
  • python实现简单fast-cgi服务,对接到nginx
  • 蓝桥云客 刷题统计
  • 持续集成与Jenkins安装使用教程
  • 分布式锁方案-Redisson
  • Linux命令-tar