跟着左神学算法(一)

仅作为个人学习笔记,大佬勿喷!

1.给定一个数组和一个基准值, 要求 小于基准值在数组左边,等于基准值在中间,大于基准值在右边

public static int[] hierarchy(int[] nums,int equivalent){
       /* 1.当前值等于判断值,跳下一个;
       * 2.当前值小于判断值,当前值和小于区后一个值交换,小于区右移一个,跳下一个;
       * 3.当前值大于判断值,当前值和大于区前一个值交换,大于区左移一个。
       * */
        if(nums==null){
            return null;
        }
        int l=-1;
        int r=nums.length;
        int i=l+1;
        while (i<r){
            if(nums[i]<equivalent){
                change(nums,i,l+1);
                l++;
                i++;
            }else if(nums[i]>equivalent){
                change(nums,i,r-1);
                r--;
            }else {
                i++;
            }
            System.out.println("i="+i+" l="+l+" r="+r);
        }
        return nums;
    }

    public static  void  change(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }

解题思路:

左边小于区右下标l,右边大于区左下标为r=nums.length

(1当前值等于判断值,跳下一个;

(2)当前值小于判断值,当前值和小于区后一个值交换,小于区右移一个,跳下一个;

(3)当前值大于判断值,当前值和大于区前一个值交换,大于区左移一个。

2.荷兰国旗问题变种
力扣 https://leetcode-cn.com/problems/first-missing-positive/

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

public static int getMinPositiveInteger(int[] nums){
       int L=0;
       int R=nums.length;
        while (L!=R){
            if(nums[L]==L+1){
                L++;
            }else if(nums[L]<=L || nums[L]>R || nums[L]==nums[nums[L]-1] ){
                change(nums,L,--R);
            }else {
                change(nums,L,nums[L]-1);
            }
        }
        return L+1;
    }

    public static void change(int[] nums,int i,int j){
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }

解题思路:
由荷兰国旗问题启发,有效区右下标L,垃圾区左下标R,

最好的情况数组里面是 1~nums.length=R,

如果大于R,则为垃圾数据

nums[L]小于L,同样属于垃圾数据

如果nums[nums[L]-1]的位置上已经放了符合条件的值,说明此时数值为重复,则归为垃圾数据

如果 num[L]==L+1,则直接下一个

其余情况,则交换对应位置数值即可

3.给定一个数组,里面只有"G"和"B", 可以所有B放在左侧,所有G放在右侧, 或者所有G放在右侧,所有B放在右侧, 但是只能相领字符之间进行交换,请问至少需要交换几次

public static int minStep( String s){
        if(s == null || s.equals("")){
            return 0;
        }
        int stepB=0;
        int b=0;
        int stepG=0;
        int g=0;
        final char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if(chars[i]=='B'){
                stepB+=i-(b++);
            }else{
                stepG+=i-(g++);
            }
        }
        return Math.max(stepB,stepG);


    }

解题思路:
当一种字母归位,就意味着B和G都已经归位了,所以只需要取B字母在左侧需要步数和G字母在左侧需要步数中的小值即可。

一个变量记录当前符合条件是第几个字母(b++/g++),下一个符合 条件字母归位需要步数(i-(b++)/i-(g++))

4.现有多根线段,开始时间点和结束时间点都为整数,最多有多少线段重叠(重叠段大于1)?

public static int getMaxCoincideLine(int[][] lines){
        //按照开始时间点排正序
        Arrays.sort(lines, Comparator.comparingInt(a -> a[0]));
        final PriorityQueue<Integer> queue = new PriorityQueue<>();
        int max=0;
        for (int[] line : lines) {
            final int start = line[0];
            final int end = line[1];
            while (!queue.isEmpty() && start>queue.peek()){
                queue.poll();
            }
            queue.add(end);
            int size=queue.size();
            max=Math.max(max,size);
        }
        return max;

    }

解题思路:
利用特殊的数据结构,小根堆(java中 PriorityQueue),堆顶为最小数,

线段按照开始时间点排正序,遍历放入小根堆,堆内比当前线段开始时间点小的弹出(因为堆内都是放的结束时间点,比当前线段开始点小,意味着线段已结束,不在当前线段范围内),再把当前线段的结束时间点放入小根堆,此时堆内数量就是重叠线段数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值