跟着左神学算法(二)

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

1.超级水王

 /**
     * 超级水王,数组中某个数出现的次数超过nums.length/2 ,则称该数组有超级水王数,返回该数
     * 要求数组最多只能遍历两次,空间复杂度为O(1)
     * @param nums
     * @return
     */
    public static void  supperWaterKing(int[] nums){
        if(nums==null || nums.length==0){
            System.out.println("没有水王数");
            return;
        }

        int target=0;
        int hp=0;
        for (int num : nums) {
            if(hp==0){
                target=num;
                hp++;
            }else if(num==target){
                hp++;
            }else{

                hp--;
            }

        }
        if(hp==0){
            System.out.println("没有超级水王");
            return;
        }

        int count=0;
        for (int num : nums) {
            if(num==target){
                count++;
            }
        }
        if(count>nums.length/2)
            System.out.println("超级水王数是"+target);

    }

解题思路:
数值中每次啊删除两个不同的数,如果最后没有剩余数,则一定没有水王数。最后数组中有剩余数不一定有超级水王数,拿剩下的数再次遍历数组,获取出现次数来判断最终结果。

核心在于如何快速的删除两个不同的数。

2.转圈打印

public static  void circlePrint(int[][] nums){

        if(nums==null|| nums.length==0 || nums[0].length==0){
            return;
        }

        int leftUpRow=0;
        int leftUpList=0;
        int rightDownRow=nums.length-1;
        int rightDownList=nums[0].length-1;

        while (leftUpList<=rightDownList && leftUpRow<=rightDownRow){
            if(leftUpList==rightDownList && leftUpRow==rightDownRow){
                System.out.print(nums[leftUpRow][leftUpList]);
            }else {
                if(leftUpRow==rightDownRow){
                    for (int list = leftUpList; list <=rightDownList ; list++) {
                        System.out.print(nums[leftUpRow][list]+" " );
                    }
                }else if(leftUpList==rightDownList){
                    for (int row = leftUpRow; row <=rightDownRow ; row++) {
                        System.out.print(nums[row][leftUpList] +" " );
                    }
                }else {
                    for(int list=leftUpList;list<rightDownList;list++){
                        System.out.print(nums[leftUpRow][list] +" " );
                    }
                    for (int row = leftUpRow; row <rightDownRow ; row++) {
                        System.out.print(nums[row][rightDownList]+" "  );
                    }
                    for(int list=rightDownList;list>leftUpList;list--){
                        System.out.print(nums[rightDownRow][list]+" "  );
                    }
                    for(int row=rightDownRow;row>leftUpRow;row--){
                        System.out.print(nums[row][leftUpList] +" " );
                    }
                }

            }

            leftUpRow++;
            leftUpList++;
            rightDownList--;
            rightDownRow--;

        }



    }

解题思路:
找到左上角、右下角的旋转打印。判断左上角和右下角同一个位置时、同一行不同列时、同一列不同行时,不同行不同列四种情况打印即可

3.Z字形打印

/**
     * @Author WXK
     * @Description 之字形打印
     * @Date 10:00 2022/1/18
    **/
    public static void zigzagPrint(int[][] nums){
        if(nums==null || nums.length ==0 ||nums[0].length==0){
            return;
        }
        int rightRow=0;
        int rightColumn=0;
        int downRow=0;
        int downColumn=0;
        int endRow=nums.length-1;
        int endColumn=nums[0].length-1;
        boolean flag=false;
        while (rightRow !=endRow+1){
            print(nums,rightRow,rightColumn,downRow,downColumn,flag);
            rightRow=rightColumn==endColumn?rightRow+1:rightRow;
            rightColumn=rightColumn==endColumn?rightColumn:rightColumn+1;

            downColumn=downRow==endRow?downColumn+1:downColumn;
            downRow=downRow==endRow?downRow:downRow+1;
            flag=!flag;
        }
    
    
    
    }
    /**
     * @Author WXK
     * @Description 打印
     * @Date 14:44 2022/1/18
    **/
    public static void print(int[][] nums,int rightRow,int rightColumn,int downRow,int downColumn,boolean flag){
        if(flag){
            while (rightRow!=downRow+1){
                System.out.print(nums[rightRow++][rightColumn--]+" ");
            }
        }else {
            while (downRow!=rightRow-1){
                System.out.print(nums[downRow--][downColumn++]+" ");
            }
        }
    }

解题思路:
一定要从宏观角度观察其规律。使用两个指针,一个指针先向右移动,移动到最后一列之后,改为向下移动;另一个指针先向下移动,移动到最后一行时,改为向右移动。移动中的两个指针必定在同一斜线上。通过flag来控制方向。

4、找出数组中唯一一个出现奇数次的数 数组中只有一种数,出现奇数次,其他所有数都出现了偶数次 怎么找到这唯一出现了奇数次的数字

public static void getUnevennumber(int[] nums){

        if(nums!=null && nums.length>0){
            int number=0;
            for (int num : nums) {
                num^=number;
            }
            System.out.println(number);
        }

    }

解题思路:
0异或任何数都为该数本身,异或满足交换律,交换计算后不影响最终结果。一个数异或本身都为零

故最后剩下的一定是奇数次的数

5.寻找明星
给定一个数n,所有人的编号从0到n-1

给定一个函数 boolean know(int i, int j),

该函数表示i这个人认不认识j这个人,认识关系是单向的

有了这个函数,你可以检查认识这件事情。

规定何为明星?

1)所有人都认识这个人

2)这个人不认识自己之外的所有人

那么这个人就是明星

利用know函数,找到明星,返回明星的编号,如果没有明星返回-1。

Leetcode题目 :
https://leetcode.com/problems/find-the-celebrity/

/**
     * 系统默认给定函数
     * @param x
     * @param i
     * @return
     */
    public static boolean knows(int x, int i) {
        return true;
    }

    /**
     * 寻找明星
     * @param n
     * @return
     */
    public static int findCelebrity(int n){

        int can=0;
        for (int i = 0; i < n; i++) {
            if(knows(can,i)){
                can=i;
            }

        }
        //最后拿到can对应的数,在遍历一次,判盯can是否为明星
        //can右侧都是他不认识的,只需判断左侧  明星除了自己不认识其他人
        for(int i=0;i<can;i++){
            if(knows(can,i)){
                return -1;
            }
        }
        //所有人都认识明星
        for(int i=0;i<n;i++){
            if(!knows(i,can)){
                return -1;
            }
        }
        return can;



    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值