zoukankan      html  css  js  c++  java
  • 双指针、位运算、离散化、区间合并的手动模拟

    双指针、位运算、离散化、区间合并的手动模拟

    双指针算法:

    题目详情

    模拟:

    import java.util.Scanner;
    
    public class Main{
        static int N = 100010;
        public static void main(String[] args){
            Scanner sc = new Scanner(System.in);
            
            int n = sc.nextInt();
            int[] array = new int[N];
            int[] s = new int[N];
            for(int i = 0;i < n; i++){
                array[i] = sc.nextInt();    
            }
            int res = 0;
            for(int i = 0,j = 0;i < n;i++){
                s[array[i]]++;
                while(j<i && s[array[i]]>1){
                    s[array[j++]]--;
                }
                res = Math.max(res,i-j+1);
            }
            System.out.println(res);
        }    
    }
    

    数组元素的目标和

    import java.util.Scanner;
    
    public class Main{
        static int N = 100010;
        
        public static void main(String[] args){
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int m = sc.nextInt();
            
            int x = sc.nextInt();
            
            // 定义两个数组
            int[] a = new int[N];
            int[] b = new int[N];
            
            // 初始化两个数组
            for(int i = 0; i < n;i++){
                a[i] = sc.nextInt();
            }
            
            for(int j = 0; j < m;j++){
                b[j] = sc.nextInt();
            }
            // 法一 j不需要回退
            for(int i =0,j=m-1;i < n;i++){
                while(j>=0 && a[i]+b[j] >x) j--;
                if(j>=0 && a[i]+b[j] ==x) System.out.println(i+" "+j);
            }
            // 法二  超时的原因是j需要每次循环需要回退为0,这样大大增加计算量
            // for(int i =0,j=0;i < n;i++){
            //     while(j < m && a[i] + b[j] < x) j++;
            //     if(j < m && a[i]+b[j] == x){
            //         System.out.println(i+" "+j);
            //     }
            //     j=0;
            // }
        }
        
    }
    

    离散化:

    表示整数的离散化,

    给定值域为0~10^9 个数为10^5

    假定 a[]中的元素 1 3 100 2000 50000

    映射到下标为 0 1 2 3 4

    的过程为离散化

    有两个问题:

    1. a[]中可能有重复元素---需要去重
    2. 如何算出x在离散化后a中的值 ---二分
    3. 离散化中的二分模板最后return r+1,---加映射从1 开始,不加1 映射从0开始

    该题的解题思路以及用到的知识点:

    确定数轴上的点:

    1. 保存输入的下标
    2. 排序
    3. 去重

    查找数轴上的点:

    1. 手写二分查找所需数的位置

    上面是离散化的过程

    在数轴区间上+c:

    1. 前缀和

    题目详情:

    模拟:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Scanner;
    
    class Pairs{
         int first;
         int second;
    
        public Pairs(int first,int second){
            this.first = first;
            this.second = second;
        }
    }
    
    public class Main{
        public static void main(String[] args){
            Scanner sc = new Scanner(System.in);
            int n,m;
            // n次操作,m次询问
            n = sc.nextInt();
            m = sc.nextInt();
    
            int N = 300010; //因为需要将所有x,l,r存在数组中,这样就是n + 2m <= 300000
            //离散化的数组
            int[] a = new int[N];
            // 前缀和数组
            int[] s = new int[N];
    
            List<Integer> alls = new ArrayList<>();
            List<Pairs> add = new ArrayList<>();   //用来存n次操作
            List<Pairs> query = new ArrayList<>();  //用来存储m次询问
    
            // 将x(下标值),c需要加的值,放到add数组中,下标值放到alis中
            for(int i = 0;i < n; i++){
                int x = sc.nextInt();
                int c = sc.nextInt();
    
                add.add(new Pairs(x,c));
                alls.add(x);
            }
    
            // m次询问
            for(int i = 0; i < m; i++){
                int l = sc.nextInt();
                int r = sc.nextInt();
    
                query.add(new Pairs(l,r));
    
                alls.add(l);
                alls.add(r);
            }
            //将题目中的所需要的数轴上的点(下标值)已经存好,后面进行离散化的操作
            //1.排序,2.去重
            Collections.sort(alls);
            //去重,返回不重复数组的最后一个元素下标
            int last_index = unique(alls);
            //该subList()方法获取索引 0 到 index(不包括 index)的元素
            alls = alls.subList(0,last_index);
    
            //读取add中的下标x与c值,并且将c插入到对应数轴上
            for(Pairs item:add){
                //很巧妙,找到数轴中x的位置
                int index = find(item.first,alls);
                a[index] += item.second;
            }
    
            // 求前缀和
            for(int i = 1; i <=alls.size();i++) s[i] = s[i-1]+a[i];
    
            for(Pairs item:query){
                int l = find(item.first,alls);
                int r = find(item.second,alls);
                System.out.println(s[r]-s[l-1]);
            }
    
    
        }
        // 去重
        public static int unique(List<Integer> list){
            int j = 0;
            for(int i = 0; i < list.size(); i++){
                //直接在数组上进行修改,将不重复的元素从0-n进行排列;
                if(i == 0 || list.get(i) != list.get(i-1)){
                    list.set(j,list.get(i));
                    j++;
                }
            }
            return j;
        }
    
        // 离散化  采用二分方法
        public static int find(int x,List<Integer> alls){
            int l = 0,r = alls.size()-1;
            while(l < r){
                int mid = l+r>>1;
                if(alls.get(mid) >= x){
                    r = mid;
                }else{
                    l = mid+1;
                }
            }
            //因为该题后面需要采用前缀和,前缀和的下标从1开始,为了方便,离散化映射从1开始
            return r+1;
        }
    
    }
    

    区间合并:

    1. 按区间左端点排序
    2. 扫描整个区间,再扫描中把可能有交集的区间合并
    3. 先维护一个区间,在看I个区间的关系:包含、交 、无交集;

    题目详情

    import java.util.*;
    import java.io.*;
    
    class pairs{
        int l;
        int r;
        public pairs(int l,int r){
            this.l = l;
            this. r = r;
        }
    }
    
    public class Main{
        public static void main(String[] args){
            Scanner  sc = new Scanner(System.in);
            int n = sc.nextInt();
            pairs[] all = new pairs[n];
            for(int i = 0; i < n;i++){
                int l = sc.nextInt();
                int r = sc.nextInt();
    
                all[i] = new pairs(l,r);
            }
    
            
            Arrays.sort(all, (p, q)->{return p.l - q.l;});
            int sum =0;
            int max = Integer.MIN_VALUE;
            for(int i = 0;i < n; i++){
                if(max < all[i].l) sum++;
                max = Math.max(max, all[i].r);
            }
            System.out.println(sum);
        }
    }
    
    

    个人感觉比较好理解:

    import java.util.*;
    
    public class Main{
        private static int N = 100010;
        private static int[] a;
        private static ArrayList<int[]> list = new ArrayList();
        public static void main(String[] args){
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt();
            for(int i = 0;i < n;i++){
                a = new int[2];
                a[0] = scanner.nextInt();
                a[1] = scanner.nextInt();
                list.add(a);
            }
            //对列表中每个数组0位置元素升序排序
            list.sort(new Comparator<int[]>(){
                @Override
                //排序规则:如果传递的参数是第一个是o1,第二个是o2,比较的时候也是用o1-o2进行比较,那么就是升序;如果比较的时候是用反过来o2-o1进行比较,那么就是降序
                public int compare(int[] o1,int[] o2){
                    return o1[0] - o2[0];
                }
            });
            int k = 0;
            int r = Integer.MIN_VALUE;
            for(int a[] : list){
                //下一个区间左端点大于老区间右端点
                if(a[0] > r){
                    k++;
                }
                //更新右端点
                r = Math.max(r,a[1]);
            }
    
            System.out.println(k);
        }
    }
    

    位运算:

    N的二进制表示中第k位是几;

    1. 先把第k位移到最后一位
    2. 看个位是几

    求n的第k位(0开始)数字: n >> k & 1
    返回n的最后一位1:lowbit(n) = n & -n

    -n为n的反码 取反+1; 与运算 有0得0

    例子 x = 1010 --->10

    x = 101000 ----> 1000;

    作用:求x中1得个数

    题目详情:

    import java.util.Scanner;
    
    public class Main{
        
        public static void main(String[] args){
            Scanner sc = new Scanner(System.in);
            
            int n,m;
            n = sc.nextInt();
            
            for(int i = 0; i < n; i++){
                m = sc.nextInt();
                int count = 0;
                while(m != 0){
                    m -= lowbit(m);
                    count++;
                }
                System.out.print(count+" ");
            }
        }
        public static int lowbit(int x){
            return x & -x;
        }
        
    }
    

    结束:

    如果有错误欢迎指正,感谢各位看到最后!

  • 相关阅读:
    浅析MySQL关联left join 条件on与where的区别
    c语言 char * char** 指针 * 和**
    MVC实用构架实战(一)——项目结构搭建
    实现存储过程自动执行jobs
    Oracle 建立索引及SQL优化
    vue vhtml table里内容不换行 带省略号
    canvas lineTo 理解
    canvas quadraticCurveTo 二次贝塞尔曲线
    canvas arc 画园
    Java对象内存模型
  • 原文地址:https://www.cnblogs.com/xbhog/p/14454320.html
Copyright © 2011-2022 走看看