• 算法路漫漫(三) 荷兰国旗


     1.给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)

    /**
     * 给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,
     *  大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
     */
    @Slf4j
    public class Alg008_SeparateArr {
    
    
        @Test
        public void test(){
            for(int i=0;i<5000;i++){
                int[] arr  = generateArr();
                int[] vals = separate(arr, 0);    
                log.info("vals:{}", vals);
            }
        }
    
    
        private int[] separate(int[] arr, int target){
            if(arr.length <2){
                return arr ;
            }
            int l =0;
            for(int i=0;i<arr.length;i++){
               if(arr[i] < target){
                    swap(arr,l++,i);
               } 
            }
            return arr;
    
        }
    
    
        public static void swap(int[] arr, int i, int j) {
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    
    
        private int[] generateArr(){
            return new Random().ints(-100, 100).distinct().limit(20).toArray();
     
        }
        
    }

    解题思路: 借助一个辅助变量L下标为0, 遍历数组 比较小于sum的值,与L交换,同时L++

    2.(荷兰国旗问题)给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)

    /**
     * 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,
     *      大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
     */
    @Slf4j
    public class Alg009_NetherlandsFlag {
    
    
        @Test
        public void test(){
            for(int i=0;i<5000;i++){
                int[] arr  = generateArr();
                log.info("result:{}", change(arr, 0, arr.length-1, 0));
            }
        }
    
        // push the L close to R
        public int[] change(int[] arr, int L,int R,int target){
            int l = L-1;
            int r = R+1;
            while(L < r){
                if(arr[L] < target){
                    swap(arr,++l,L++);
                } else if(arr[L] > target){
                    swap(arr, --r,L);
                } else {
                    L++;
                }
            }
            return arr;
        }
    
        public static void swap(int[] arr, int i, int j) {
            int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
    
    
        private int[] generateArr(){
            return new Random().ints(-100, 100).distinct().limit(20).toArray();
     
        }
        
    }

    解题思路: 给数组规定左边界和右边界,以及移动的指针i, 一共有三种比较

    1. arr[i] < num, i和左边界的下一位交换,同时左边界右扩一位,i++

    2. arr[i] == num, i++

    3. arr[i] > num, i和右边界的前一位交换,同时右边界左扩一位,i原地不动

  • 相关阅读:
    USACO 5.4.2 tour
    USACO 4.4.2 milk6
    USACO 6.1.2 rectbarn
    USACO 4.1.4 cryptcow
    VC++学习笔记之ActiveX
    VC++学习笔记之MFC应用程序创建/执行顺序和MFC运行机制
    FusionCharts Free(一)使用方法和应用实例(asp.net)
    FusionCharts Free(二)使用方法详细解析
    VC++学习笔记之MFC消息映射机制
    MFC基本知识沉淀
  • 原文地址:https://www.cnblogs.com/hlkawa/p/14942911.html
Copyright © 2020-2023  润新知