leetcode 记录

前缀和问题

对于 leetcode 上的一类问题:
一个数组中,连续子数组 ,满足一定的条件的问题,这一类问题基本上有 如下两种思路:
以 i 结尾 的 dp 数组应用,特别适合连续子数组;
滑动窗口;也特别适合连续数组的约束;

我约到的题目, 连续子数组 的 和 最大, 用 dp;
连续子数组 的和 与 k 的关系, 大于k,小于 k,等于k,通常就是 使用 前缀和数组;
前缀和 数组 在遍历的时候,可以生产, 然后可以用一些特殊的数据结构来加快 在前缀和中的查找;

比如 ==k 的 子数组的个数,可以使用 map 记录;
小于 k 的数, 可以使用一个 treeset 记录 前缀和元素, 能够做到 logN 的方式来查找。

另外一类就是 滑动窗口的问题, 通常也是可以使用额外的空间结构来记录 相应的特性元素,比如滑动的时候,记录最小值,使用最小堆; 记录元素出现的次数 来动态维护 相应的特性;

滑动窗口,连续子数组, 前缀和,辅助结构,基本上就能够处理 大多数的这类问题了。

甚至,都可以应用到 二维数组中; #### 363. 矩形区域不超过 K 的最大数值和

连续的 子矩阵,也是一个换皮的题目,可以使用 前缀和,只需要 遍历,行或者列。

另外一道题:
给你一个数组, 可以做K次操作,每次操作,可以加一, 然你求出 至多 k次操作之后, 出现频率最大的数;

这道题,可以排序,然后 遍历每个元素,假设最大频率元素为a[i], 然后可以向前 找 [l, r] 的区间,区间长度为 n,那么只需要 区间和 与 n * a[i] 的diff 小于 k 就行; 所以 可以利用前缀和辅助数组来帮助加快查询;

这是一道比较隐秘的 前缀和问题;

子数组最大最小值问题

1, 给定一个数组,对于其中的连续子数组;
比如设定连续的长度m; 有一类问题:

  • 长度为m中的 最大值或者最小值的 当中最大或者最小的;
  • 最大值或者最小值 的差值构成的数组中; 最大的是?

这两个问题,都可以通过 设置一个 logM 的最大最小堆来维护滑动窗口中的最大值或者最小值;来获得一个接近 o(N)的复杂度;

两外一类就是不设定M,M 是可以任意值的, 这个最大最小的差值的一些特型?

看起来怎么都需要一个 n2的解法,另外最大最小差值,就有N2个;
我们看看这样一个 例子, 6,9,4,7,4,1; 对于满足某种条件的值; 用最大最小值队列,维护 Ai-j 的最大最小值;
知道无法满足,最大值减去最小值<N;
我们先用 优先级队列来做;维护 Ai-j 最大最小值;
固定i, 然后探索J。 看j 能最远达到什么地方,用 队列维护最大最小值,就可以复用;
比如N= 4;
i=6; j 只能到达 4; 队列就是 4 6 9; 9 6 4;
remove 6 : 队列 4,9; 9;4
i=9; j 还是只能4; 队列就是 4; 4;

i=4; j 可以到1; 队列 1 4 4 7; 7 4 4 1;一直遍历;
最坏,N logN; 没有 题解中使用单调队列来的快; 因为有很多信息是不需要的;

对于求和的问题??
1 2 ,3 ,9, 7,6, 5
目前只能想到, 记录最大值,最小值,然后,跳过一些不必要的计算;依旧还是个N2的局;
求和的问题是一个变换, 求出最大值的和,求出最小值的和,然后 Sum(max)- sum(min)
求最大,最小值, 是leetcode-907;
利用的单调栈, 和 求 最大矩形面积是一样的题; 单调栈,可以开一个专题,是弱项;

单调栈求最小值:

  • 找的就是 最小值或者最大值,然后求两边 大于或者是小于我的数值;

  • 为什么 单 stack.top() >= cur 的时候, 就需要计算呢?
    因为 stack.top() 找到了一个cur,已经比我小了,往后再找就没有意义了,不可能比我大了。

  • 为什么要 == cur,其实大多数时候,不需要等于也是可以得

  • 为了方便计算,最好是,在 array 的最后加入一个 0元素,保证在for循环就能处理所有的元素

     //和最大矩形面积是一个思路;
     // 找到一种方法, 对于每一个 元素 a, 能够很方便的知道,我 左边 大于我的个数, 右边大于我的个数
     //也就是 我处于谷底的个数, 这种特别是和 单调栈,栈中存放 元素的下标
     //  1 7  5  8 9  4 10
     // 比如 1 5  8 9 ,看4 的时候, 简直一个套路;
    
        int len = arr.length;
        if (len == 1)
            return arr[0];
        Stack<Integer> s = new Stack<>();
        long ans = 0;

        for (int i = 0; i <= len; i++) {
            int cur = 0;
            if(i!=len) cur =arr[i];

            while (!s.isEmpty() && arr[s.peek()] >= cur) {
                Integer index = s.pop();
                int rangeLeft = s.isEmpty() ? -1 : s.peek();
                ans += (long) (index - rangeLeft) * (i - index) * arr[index];
                ans %= mod;
            }
            s.add(i);
        }

        return (int) (ans % mod);

二分查找汇总

s = 0, e = n-1; while(s<=e) ; 这种情况下 e = m-1; s=m+1;
如果 e = m 或者 s=m; 是可能存在死循环的,一定要注意;如果非得 要 e=m;注意处理 s=e 的情况;
循环结束的时候,有两种 e > s; e 可能小于0 或者 S > n; 看情况要不要处理;

leet-34: 查找K,可能有多个K,最左边的K 和最右边的K;
找到 K 的时候,不要反悔, 记录 ans = m 就行; 可以处理只有一个 k的情况;

leet-33: 螺旋数组查找
//螺旋数组,画图,最好理解; 一共是两个左右线段, mid 在第一个还是第二个,一共4种情况,很直观;
leet-74; 搜索二维数组,转化为一维就行
leet-153: 螺旋数组的最小值:
值得记录: 出现了 e = m 的情况; 其实也可以画线段处理,但是要处理很多情况;
s-e递增, m = 最小值; s=e的情况;等等;官方的解法,就是 从 nums[m] < nums[e]
这种情况来处理;避免很多edge case 讨论,不太容易想到;
leet-162: 寻找峰值:
假设 数组只有一个 递减 和 递增 ,那么 肯定是能找到的峰值的,那么就有了 二分查找,m。 如果m 处递增,则往后继续,如果递减,往前继续; 否则满足条件返回;

并查集

/**
 * 并查集,特别适合解决,两个 元素, 是否在一个 集合里, 是否在连通图里面;
 * 并且非常适合,不断有新元素加入到整个集合里面来;
 */
public class UnionFind {
    /// 记录每个元素的parent;
    /// 通常需要知道 value 的scope,同时scope 不能太大,否则开辟数组需要很大的空间;
    int[] parents;

    public UnionFind(int size){
        parents = new int[size];
        for(int i=0; i< size; i++)
            parents[i] = i;
    }

    /**
     * 使用压缩路径的方式
     * @param v
     * @return
     */
    public int findRoot(int v){
        if(v!=parents[v]){
            parents[v] = findRoot(parents[v]);
        }
        return parents[v] ;
    }

    /**
     * union 的方式决定了 findRoot的时间复杂度;
     * v1-....-root;  v2...root
     * @param v1
     * @param v2
     */
    public void union(int v1, int v2 ){
        int root1 = findRoot(v1);
        int root2 = findRoot(v2);
        parents[root1] = root2;
    }

    public boolean inSameSet(int v1, int v2){
        int root1 = findRoot(v1);
        int root2 = findRoot(v2);
        return root1 == root2;
    }


    public static void main(String[] args) {
        UnionFind uf = new UnionFind(10);
        System.out.println(uf.findRoot(1));
        System.out.println(uf.inSameSet(1,3));
        uf.union(1,3);
        System.out.println(uf.inSameSet(1,3));
        uf.union(2,4);
        uf.union(1,2);
        System.out.println(uf.inSameSet(1,4));


    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,513评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,312评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,124评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,529评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,937评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,913评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,084评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,816评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,593评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,788评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,267评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,601评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,265评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,158评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,953评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,066评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,852评论 2 277

推荐阅读更多精彩内容