标签: 滑动窗口

LeetCode刷题【1610】可见点的最大数目

给你一个点数组 points 和一个表示角度的整数 angle ,你的位置是 location ,其中 location = [posx, posy]points[i] = [xi, yi] 都表示 X-Y 平面上的整数坐标。

最开始,你面向东方进行观测。你 不能 进行移动改变位置,但可以通过 自转 调整观测角度。换句话说,posxposy 不能改变。你的视野范围的角度用 angle 表示, 这决定了你观测任意方向时可以多宽。设 d 为你逆时针自转旋转的度数,那么你的视野就是角度范围 [d - angle/2, d + angle/2] 所指示的那片区域。

对于每个点,如果由该点、你的位置以及从你的位置直接向东的方向形成的角度 位于你的视野中 ,那么你就可以看到它。

同一个坐标上可以有多个点。你所在的位置也可能存在一些点,但不管你的怎么旋转,总是可以看到这些点。同时,点不会阻碍你看到其他点。

返回你能看到的点的最大数目。

 

示例 1:

输入:points = [[2,1],[2,2],[3,3]], angle = 90, location = [1,1]
输出:3
解释:阴影区域代表你的视野。在你的视野中,所有的点都清晰可见,尽管 [2,2] 和 [3,3]在同一条直线上,你仍然可以看到 [3,3] 。

示例 2:

输入:points = [[2,1],[2,2],[3,4],[1,1]], angle = 90, location = [1,1]
输出:4
解释:在你的视野中,所有的点都清晰可见,包括你所在位置的那个点。

示例 3:

输入:points = [[1,0],[2,1]], angle = 13, location = [1,1]
输出:1
解释:如图所示,你只能看到两点之一。

 

提示:

  • 1 <= points.length <= 105
  • points[i].length == 2
  • location.length == 2
  • 0 <= angle < 360
  • 0 <= posx, posy, xi, yi <= 100
Related Topics
  • 几何
  • 数组
  • 数学
  • 排序
  • 滑动窗口

  • 👍 113
  • 👎 0
  • 相对坐标信息转换为弧度信息,排序后滑窗统计
    前置基本知识

    1. 弧度,360° = π * 2 的弧度,180° = π 弧度
    2. 滑动窗口

    基本步骤

    1. List<List<Integer>> points数组和List<Integer> location数组分别计算,得到各个点对应的弧度值,如果你直接用角度计算的话也一样
    2. 如果这个点和List<Integer> location位置相同,则这个点永远可见,不做计算,并计数永远可见点数量加1
    3. Math.atan2计算的弧度值是从π范围的,直接用于后续计算不行,所以我们将0范围内的数据统一加,即将最终结果映射到0区间中
    4. 前面有永远可见点占位清理下,同时记得对现在已经计算出来的弧度数组重新排序,因为题面中给的List<List<Integer>> points数组位置顺序并非按照弧度顺序排序的
    5. 转链为环,因为这边得到结果是一个数组,不方便计算从结尾到开头时候的情况,即滑窗开始在结尾,滑窗结束在开头的情况,所以我们使用了常用的作法之一,数组复制双倍,这样环的数据就可以处理了,不过不需要整个数组复制双倍,只需把弧度0到窗口弧度内的数据重新接在数组结尾即可
    6. 接下来就是常规的滑动窗口统计窗口内最大数量的问题了,比较简单,不做赘述了
    7. 记得最终结果要加上之前统计到的永远可见点数量

    没做过画图或者3d之类的开发的话这题拿到手可能有点懵,有幸之前学习研究过一段时间ThreeJS,空间、平面信息的转换上能稍微有点感觉,拿到手之后思路还是非常明确的。就是各种边边角角的细节逻辑采坑略多,想想下location点是一个相机Camera,这个angle就是对应的相机镜头的视角应该还是比较好理解的

    从坐标转换为弧度,

    最终将弧度信息映射在从0区间的数据

    代码

    class Solution {
        public int visiblePoints(List<List<Integer>> points, int angle, List<Integer> location) {
            double x1 = (double) location.get(0);
            double y1 = (double) location.get(1);
    
            double[] radianList = new double[points.size()];
            double radianWin = angle * Math.PI / 180;
            int alwaysSee = 0;
    
            int idx = -1;
            for (List<Integer> point : points) {
                double x2 = (double) point.get(0);
                double y2 = (double) point.get(1);
                if (x1 == x2 && y1 == y2){
                    alwaysSee++;
                    continue;
                }
                radianList[++idx] = Math.atan2(y2-y1,x2-x1);
                if (radianList[idx] < 0){
                    radianList[idx] += Math.PI * 2;
                }
            }
            Arrays.sort(radianList);
    
            if (alwaysSee>0){
                double[] tmp = new double[radianList.length-alwaysSee];
                System.arraycopy(radianList,alwaysSee,tmp,0,radianList.length-alwaysSee);
                radianList = tmp;
            }
    
            //开始滑窗统计
            int l = 0;
            int r = 0;
            int max = 0 ;
            //窗口初始化
            while (r + 1 < radianList.length && radianList[r+1] <= radianList[l] + radianWin ){
                r++;
                max = r-l+1;
            }
    
            //在原来的radianList数组之后,在拼上一段radianWin弧度的数据,这段数据为从弧度0开始到弧度radianWin之内的所有数据
            //而这里得0到滑窗弧度范围内的点的值
            if (radianList.length>0 && radianList[l] <= radianWin){
                double[] tmp = new double[radianList.length + max];
                System.arraycopy(radianList,0,tmp,0,radianList.length);
                System.arraycopy(radianList,0,tmp,radianList.length,max);
                for (int i = radianList.length; i < tmp.length; i++) {
                    tmp[i] += Math.PI * 2;
                }
                radianList = tmp;
            }
            //开始滑动
            while (l<radianList.length && radianList[l]+ radianWin <= radianList[radianList.length-1]){
                l++;
                while (r + 1 < radianList.length && radianList[r+1] <= radianList[l]+radianWin ){
                    r++;
                }
                max = Math.max(max,r-l+1);
            }
           return max+alwaysSee;
        }
    }

    LeetCode刷题【438】找到字符串中所有字母异位词

    给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

    异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

     

    示例 1:

    输入: s = "cbaebabacd", p = "abc"
    输出: [0,6]
    解释:
    起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
    起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
    

     示例 2:

    输入: s = "abab", p = "ab"
    输出: [0,1,2]
    解释:
    起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
    起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
    起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
    

     

    提示:

    • 1 <= s.length, p.length <= 3 * 104
    • s 和 p 仅包含小写字母
    Related Topics
    • 哈希表
    • 字符串
    • 滑动窗口

  • 👍 929
  • 👎 0
  • 滑动窗口+哈希表统计,联动可以参考下76题最小覆盖子串

    类似的可以看下76题,非常相似
    滑动窗口,带注释
    区别就是76题是非固定长度窗口,本题中窗口长度固定

    class Solution {
        public List<Integer> findAnagrams(String s, String p) {
            if (s.length()<p.length()){
                return new ArrayList<>();
            }
            int[] arr =  new int[26];
            int count = 0;
            for (int i = 0; i < p.length(); i++) {
                arr[p.charAt(i)-'a']++;
                if (arr[p.charAt(i)-'a'] == 1){
                    count++;
                }
                arr[s.charAt(i)-'a']--;
                if (arr[s.charAt(i)-'a'] == 0){
                    count--;
                }
            }
            List<Integer> res = new ArrayList<>();
            if (count == 0){
                res.add(0);
            }
            int idx = p.length()-1;
            while (++idx < s.length()){
                arr[s.charAt(idx-p.length())-'a']++;
                if (arr[s.charAt(idx-p.length())-'a'] == 1){
                    count++;
                }
                arr[s.charAt(idx)-'a']--;
                if (arr[s.charAt(idx)-'a'] == 0){
                    count--;
                }
                if (count == 0){
                    res.add(idx-p.length()+1);
                }
            }
            return res;
        }
    }

    LeetCode刷题【76】最小覆盖子串

    给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 ""

     

    注意:

    • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
    • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

     

    示例 1:

    输入:s = "ADOBECODEBANC", t = "ABC"
    输出:"BANC"
    

    示例 2:

    输入:s = "a", t = "a"
    输出:"a"
    

    示例 3:

    输入: s = "a", t = "aa"
    输出: ""
    解释: t 中两个字符 'a' 均应包含在 s 的子串中,
    因此没有符合条件的子字符串,返回空字符串。

     

    提示:

    • 1 <= s.length, t.length <= 105
    • st 由英文字母组成

     

    进阶:你能设计一个在 o(n) 时间内解决此问题的算法吗?
    Related Topics
  • 哈希表
  • 字符串
  • 滑动窗口

  • 👍 1957
  • 👎 0
  • 滑动窗口,带注释

    一样的,就是统计窗口内待匹配字符出现次数

    1. 统计原t字符串中各个字符的数量
    2. 在字符串s中进行窗口移动操作
    3. 如果还有需要匹配的字符数量,则往右扩展右边界增大窗口
    4. 如果字符数量都匹配达成,则左边界往右可移动缩小窗口
    5. 在窗口移动过程中取到最小的那个子串

    代码

    class Solution {
        public String minWindow(String s, String t) {
            int[] arr = new int[128];
            HashSet<Character> hashSet = new HashSet<>();
            for (int i = 0; i < t.length(); i++) {
                arr[t.charAt(i)]++;
                hashSet.add(t.charAt(i));
            }
            int count = hashSet.size();
            //count 表示待匹配字符个数
            int l = 0;
            int r = -1;
            int minL = 0;
            int minLen = Integer.MAX_VALUE;
    
            while (r < s.length()){
                if (count == 0){
                    //移动左边,尝试缩减长度
                    arr[s.charAt(l)]++;
                    //左边界每往右移动一个字符 在在arr[]中这个字符个数加1
                    if (hashSet.contains(s.charAt(l)) && arr[s.charAt(l)] == 1){
                        // 如果这个字符在hashSet中,且结果等于1,即表示是从匹配成了变为缺少匹配个数的状态,那么count++;
                        count++;
                    }
                    //移动左边
                    l++;
                }else{
                    //移动右边边
                    r++;
                    if (r == s.length()){
                        break;
                    }
                    arr[s.charAt(r)]--;
                    //右边界每新增一个字符, 在arr[]中减去这个字符个数减1
                    if (hashSet.contains(s.charAt(r)) && arr[s.charAt(r)] == 0){
                        //    如果这个字符在hashSet中,如果结果为0 了表示都匹配到了,则count--;
                        count--;
                    }
                }
                if (count==0 && r - l < minLen){
                    //记下最小子串
                    minLen = r - l;
                    minL = l;
                }
            }
            return minLen==Integer.MAX_VALUE?"":s.substring(minL,minL+minLen+1);
        }
    }

    LeetCode刷题【面试题 17.17】多次搜索

    给定一个较长字符串big和一个包含较短字符串的数组smalls,设计一个方法,根据smalls中的每一个较短字符串,对big进行搜索。输出smalls中的字符串在big里出现的所有位置positions,其中positions[i]smalls[i]出现的所有位置。

    示例:

    输入:
    big = "mississippi"
    smalls = ["is","ppi","hi","sis","i","ssippi"]
    输出: [[1,4],[8],[],[3],[1,4,7,10],[5]]
    

    提示:

    • 0 <= len(big) <= 1000
    • 0 <= len(smalls[i]) <= 1000
    • smalls的总字符数不会超过 100000。
    • 你可以认为smalls中没有重复字符串。
    • 所有出现的字符均为英文小写字母。
    Related Topics
  • 字典树
  • 数组
  • 哈希表
  • 字符串
  • 字符串匹配
  • 滑动窗口

  • 👍 41
  • 👎 0
  • smalls数组构建字典树

    1. smalls数组构建字典树
    2. big数组从第i位开始到结尾的子序列拿到字典树上匹配,i从0开始分别求解,直到结束
    3. 因为匹配的时候需要知道当前字典树上字符串结束节点是哪个字符的,所以字典树的节点需要额外记录下各自归属与smalls数组中对应字符串的下标
    4. 在树上匹配的过程中,但凡匹配到了一个结束字符,就在结果数组的对应这个字符串下标的子数组中插入一个当前匹配的big字符串子序列的开始下标

    代码

    class Solution {
        public int[][] multiSearch(String big, String[] smalls) {
            Trie trie = new Trie();
            trie.smallsCount = smalls.length;
            trie.insert(smalls);
            return trie.search(big);
        }
    
    
        public class Trie{
    
            Node tree;
            int smallsCount = 0;
    
            public Trie(){
                tree = new Node();
            }
    
            void insert(String[] strArr){
                for (int idx = 0; idx < strArr.length; idx++) {
                    Node cur = tree;
                    String str = strArr[idx];
                    int i = -1;
                    while (++i < str.length()){
                        int child = str.charAt(i)-'a';
                        if (cur.children[child] == null){
                            cur.children[child] = new Node();
                        }
                        cur = cur.children[child];
                    }
                    cur.flag = true;
                    cur.smallIndex = idx;
                }
            }
    
            int[][] search(String str){
                int[][] res = new int[smallsCount][];
                List<List<Integer>> list = new ArrayList<>();
                for (int i = 0; i < smallsCount; i++) {
                    list.add(new ArrayList<>());
                }
    
                for (int i = 0; i < str.length(); i++) {
                    String subStr = str.substring(i);
                    Node cur = tree;
                    int idx = -1;
                    while (cur != null && ++idx < subStr.length()){
                        char c = subStr.charAt(idx);
                        if (cur.children[c-'a'] != null){
                            cur = cur.children[c-'a'];
                            if (cur.flag){
                                list.get(cur.smallIndex).add(i);
                            }
                        }else{
                            break;
                        }
                    }
                }
                for (int i = 0; i < list.size(); i++) {
                    res[i] = list.get(i).stream().mapToInt(Integer::intValue).toArray();
                }
                return res;
            }
    
    
    
    
            class Node{
                boolean flag = false;
                Node[] children;
                int smallIndex = -1;
                public Node(){
                    children = new Node[26];
                }
            }
        }
    }

    LeetCode刷题【剑指 Offer II 014】字符串中的变位词

    给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

    换句话说,第一个字符串的排列之一是第二个字符串的 子串

     

    示例 1:

    输入: s1 = "ab" s2 = "eidbaooo"
    输出: True
    解释: s2 包含 s1 的排列之一 ("ba").
    

    示例 2:

    输入: s1= "ab" s2 = "eidboaoo"
    输出: False
    

     

    提示:

    • 1 <= s1.length, s2.length <= 104
    • s1s2 仅包含小写字母

     

    注意:本题与主站 567 题相同: https://leetcode-cn.com/problems/permutation-in-string/

    Related Topics
  • 哈希表
  • 双指针
  • 字符串
  • 滑动窗口

  • 👍 29
  • 👎 0

  • 滑动窗口基本思路

    基本滑动窗口算法
    挪一格,修改一下统计数量,然后对比两个数组内是否相同

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
            
            int[] count = new int[26];
            int[] window = new int[26];
            int idx = -1;
            while (++idx < s1.length()){
                count[s1.charAt(idx)-'a']++;
                window[s2.charAt(idx)-'a']++;
            }
            if (Arrays.equals(count,window)){
                return true;
            }
            idx--;
            while (++idx < s2.length()){
                System.out.println( idx );
                window[s2.charAt( idx - s1.length() ) - 'a']--;
                window[s2.charAt( idx ) - 'a']++;
                if (Arrays.equals(count,window)){
                    return true;
                }
            }
            return false;
        }
    
    }

    滑动窗口diffArr判断算法,判断26个字母数量是否为0,如果是都是0则代表能匹配

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
    
            int[] diffArr = new int[26];
            int idx = -1;
            int diffCount = 0;
            while (++idx < s1.length()){
                diffArr[s1.charAt(idx)-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
            }
            boolean flag = true;
            for (int i = 0; i < 26; i++) {
                if (diffArr[i]!=0){
                    flag =false;
                    break;
                }
            }
            if (flag){
                return true;
            }
            --idx;
            while (++idx < s2.length()){
                diffArr[s2.charAt(idx-s1.length())-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
                flag = true;
                for (int i = 0; i < 26; i++) {
                    if (diffArr[i]!=0){
                        flag =false;
                        break;
                    }
                }
                if (flag){
                    return true;
                }
            }
            return false;
        }
    
    }

    第二种滑动窗口的理解稍微绕个弯,每当diffArr中有一个不是0的,说明有一个差异点,
    然后接下来窗口滑动过程中 需要在修改前判断

    1. 这个值是不是0,如果是0,修改了之后diffCount需要加1,
    2. 如果不是0.修改之后会不会变0.如果会变0,diffCount减1
    3. 如果修改后不会变0,则diffCount不需要变更

    if判断太多,效率甚至不如上一个遍历一下长度只有26的diffArr数组

    class Solution {
        public boolean checkInclusion(String s1, String s2) {
            if (s1.length()>s2.length()){
                return false;
            }
    
            int[] diffArr = new int[26];
            int idx = -1;
            int diffCount = 0;
            while (++idx < s1.length()){
                diffArr[s1.charAt(idx)-'a']++;
                diffArr[s2.charAt(idx)-'a']--;
            }
            int i = -1;
            while (++i<26){
                diffCount += diffArr[i]==0?0:1;
            }
            if (diffCount==0){
                return true;
            }
    
            --idx;
            while (++idx < s2.length()){
                int before = s2.charAt(idx-s1.length())-'a';
                int current = s2.charAt(idx)-'a';
                if (before == current){
                    continue;
                }
                if (diffArr[before]==-1){
                    diffCount--;
                }
                if (diffArr[before] == 0){
                    diffCount++;
                }
                diffArr[before]++;
    
                if (diffArr[current]==1){
                    diffCount--;
                }
                if (diffArr[current]==0){
                    diffCount++;
                }
                diffArr[current]--;
                if (diffCount == 0){
                    return true;
                }
            }
            return false;
        }
    
    }

    LeetCode刷题【剑指 Offer 48】最长不含重复字符的子字符串

    请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

     

    示例 1:

    输入: "abcabcbb"
    输出: 3 
    解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
    

    示例 2:

    输入: "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
    

    示例 3:

    输入: "pwwkew"
    输出: 3
    解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
         请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
    

     

    提示:

    • s.length <= 40000

    注意:本题与主站 3 题相同:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

    Related Topics
  • 哈希表
  • 字符串
  • 滑动窗口

  • 👍 392
  • 👎 0
  • 一般解法,一步步分析实现

    一顿分析

    以字符串abcabcbb为例

    1. a的时候,最长为1,这个没啥问题 此时为1
    2. ab的时候,前面有了a为1,而b又不在前面的a中,所以可以由前面的长度加1得到 此时为2
    3. abc的时候,和前面的情况一样,新增的字符c在前面的范围中不存在则继续加1长度 此时长度为3
    4. abca的时候,新增了个a,在前面不重复的长度为3的字符abc中找到了一个相同的,他的下标为0,那么只能从这个下标往后和新增的a组成最长不重复子串了,下标相差求得 此时长度为3
    5. abcab的时候,比前面又多了个b,再次在前面的一个最长子串中尝试寻找b,发现存在,得到其下标为1,照样当前下标和查找到的下标求得新的最长子串长度为3
    6. abcabc的时候,又多了个c,依旧重复上面的 此时长度为3
    7. abcabcb,比前面多了个b,前面一个的最长子串为abc,查找得到了有重复的b,下标为4,和当前下标5求得新的最长子串长度为2
    8. abcabcbb,再次和前面的最长子串cb比较查找,最终得到当前最长子串长度为1
    9. 最终所有的情况中最长的为3

    代码

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            if (s.length() == 0){
                return 0;
            }
            char[] arr = s.toCharArray();
            int[] dp = new int[s.length()];
            dp[0] = 1;
            int idx = 0;
            int max = 1;
            while (++idx < s.length()){
                int existIdx = existIdx(arr,idx - dp[idx-1]-1,idx-1,arr[idx]);
                if (existIdx==-1){
                    dp[idx] = dp[idx-1]+1;
                }else{
                    dp[idx] = idx-existIdx;
                }
                max = Math.max(max,dp[idx]);
            }
            return max;
        }
    
        public int existIdx(char[] arr , int left , int right , char c){
            while (++left <= right){
                if (arr[left] == c){
                    return left;
                }
            }
            return -1;
        }
    }

    至于查找位置用的existIdx方法,这里的不同单个字符的数量比较有限,直接遍历查找即可。不是太大的性能问题

    LeetCode刷题【487】最大连续1的个数 II

    给定一个二进制数组 nums ,如果最多可以翻转一个 0 ,则返回数组中连续 1 的最大个数。

     

    示例 1:

    输入:nums = [1,0,1,1,0]
    输出:4
    解释:翻转第一个 0 可以得到最长的连续 1。
         当翻转以后,最大连续 1 的个数为 4。
    

    示例 2:

    输入:nums = [1,0,1,1,0,1]
    输出:4
    

     

    提示:

    • 1 <= nums.length <= 105
    • nums[i] 不是 0 就是 1.

     

    进阶:如果输入的数字是作为 无限流 逐个输入如何处理?换句话说,内存不能存储下所有从流中输入的数字。您可以有效地解决吗?

    Related Topics
  • 数组
  • 动态规划
  • 滑动窗口

  • 👍 94
  • 👎 0
  • 【动态桂花】详细分析总结过程

    自己写个例子试一下看看
    [1,0,1,1,0,0,1,1,1,1,0]
    定义两个值,一个定义当遍历中的这段有连续多长了。
    另一个表示如果翻转这个位置的0变成1能得到连续多长的1字符,如果不是0则之前的连续长度加1

    如下
       1,0,1,1,0,0,1,1,1,1,0
    a) 1 0 1 2 0 0 1 2 3 4 0
    b) 1 2 3 4 3 1 2 3 4 5 5
    
    分析下
    1. 第一位为1,则a表示的,当前可以得到的连续长度为1,b同样,如果第一位为0的话,a等于0,b依旧等于1
    2. 第二位为0,a的连续性中断了,此时a等于0,b的话可以在之前的a等于1的后面转换一个得到长度为2
    3. 第三位为1,此时a继续等于1,b可以在之前的长度上继续延长得到3
    4. 第四位为1,同上一步a等于2,b等于4
    5. 第五位为0,a的连续性中断了,此时a等于0。如果翻转这里的0可以得到和前面的a等于相连,得到长度为3的连续1数字
    6. 第六位依旧为0,a依旧等于0,b只能和前面的第五位的时候的a等于0相连得到长度为1的连续数字1
    7. 第七位变为了1,a这里等于1了,b可以连着前面的,此时b等于2
    8. 第八、九、十位,都是1,按照前面的规律依次叠加,最终a等于4,b等于5
    9. 最后第十一位0,这里的a再次变为0,而把这里的0翻转为1的话只能和前面的第十位的a等于4相连得到一个连续5位的数组1
    10. 在这个过程中保存b得到的最大值

    确实,动态规划这个问题的代码本身并不是非常难写,困难的是如何总结归纳出正确的转移方程,如何定义出正确的dp数组赋予正确的定义

    //当前位置为0 
    dp[i][0] = 0 
    dp[i][1] = dp[i-1][0]+1 
    //当前位置为1 
    dp[i][0] = dp[i-1][0]+1 
    dp[i][1] = dp[i-1][1]+1

    代码

    class Solution {
        public int findMaxConsecutiveOnes(int[] nums) {
            int[][] dp = new int[nums.length][2];
            dp[0][0] = nums[0];
            dp[0][1] = 1;
            int idx = 0;
            int max = 1;
            while (++idx < nums.length){
                dp[idx][0] = nums[idx] == 0?0:dp[idx-1][0]+1;
                dp[idx][1] = nums[idx] == 0?dp[idx-1][0]+1:dp[idx-1][1]+1;
                max = Math.max(max,dp[idx][1]);
    //            System.out.println(Arrays.toString(dp[idx]));
            }
            return max;
        }
    }

    继续优化的版本就省略了,其实看下上面的分析步骤就可以自己非常容易的总结出如何进一步优化了