【迎战蓝桥】 算法·每日一题(详解+多解)-- day5

目录

1. 数组中出现次数超过一半的数字

2. 二进制中1的个数

3. 替换空格


【大家好,我是爱干饭的猿,如果喜欢这篇文章,点个赞关注一下吧,后续会一直分享题目与算法思路


1. 数组中出现次数超过一半的数字

描述

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

数据范围:n ≤ 50000,数组中元素的值 100000 ≤ val ≤ 10000

要求:空间复杂度:O(1)O(1),时间复杂度 O(n)O(n)

【迎战蓝桥】 算法·每日一题(详解+多解)-- day5_第1张图片

解题思路:

1. 方法一:我们可以使用map,根据map的键值对,将数组元素存入map中,相同key值的value值+1,当当前key的value值大于数组元素一半时,return key即可。

2. 方法二:我们发现如果存在一个数字出现的次数超过数组长度的一半,当此数组排序后,出现次数最多的数字,一定在中间位置

3. 方法三:查询的本质是排除,所以我们可以先定义一个target 指向数组第一个元素,times 指出现次数,然后向后遍历,当后一个元素与target 相同时,times++;当后一个元素与target 不相同时,times --;当times == 0时,将当前元素赋值给 target。循坏结束 target 值就是出现次数最多的数字,然后遍历数组得到target出现的次数,如果大于数组元素一半时,return target 即可。

方法一:代码如下: 

    // 方法一 利用map 键值对
    public int MoreThanHalfNum_Solution1(int [] array) {
        if(array.length == 0 || array ==null){
            return 0;
        }
        int half = array.length >> 1;

        Map map = new LinkedHashMap<>();
        for (int i = 0; i < array.length; i++) {
            if(map.containsKey(array[i])){
                // map中存在当前key 时,value + 1
                map.replace(array[i],map.get(array[i])+1);
            }else {
                // map中不存在当前key 时,存入key,并将value 置为1
                map.put(array[i],1);
            }

            if(map.get(array[i]) > half){
                // 当前key的value值大于数组元素一半时,key就是所求值
                return array[i];
            }
        }
        return 0;
    }

方法二:代码如下: 

    // 方法二 数组排序
    public int MoreThanHalfNum_Solution2(int [] array) {
        if(array.length == 0 || array == null){
            return 0;
        }
        int half = array.length >> 1;
        Arrays.sort(array);
        int target = array[half];
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            if(target == array[i]){
                count++;
            }
        }
        return count > half ? target : 0;
    }
// 如果确定存在一个数字出现的次数超过数组长度的一半,return array[array.length/2]即可
 public int MoreThanHalfNum_Solution(int [] array) {
        if(array.length == 0 || array == null){
            return 0;
        }
        return array[array.length/2];
    }

方法三:代码如下: 

    // 方法三 查询的本质是排除
    public int MoreThanHalfNum_Solution3(int [] array) {
        if(array.length == 0 || array == null){
            return 0;
        }
        int half = array.length >> 1;

        int target = array[0];
        int times = 1;
        for (int i = 1; i < array.length; i++) {
            if(times == 0){
                // 当times == 0时,将当前元素赋值给 target
                target = array[i];
                times = 1;
            }else if(target == array[i]){
                // 当后一个元素与target 相同时,times++
                times++;
            }else {
                // 当后一个元素与target 不相同时,times--
                times--;
            }
        }

        times = 0;
        for (int i = 0; i < array.length; i++) {
            if(target == array[i]){
                times ++;
            }
        }
        return times > half ? target : 0;
    }

2. 二进制中1的个数

描述

输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

【迎战蓝桥】 算法·每日一题(详解+多解)-- day5_第2张图片

解题思路:

1. 方法一:我们知道只有1&1 = 1,其余0&0 = 0,1&0 = 0,0&1 = 0。

所以我们可以将整数的二进制每一位按位&1操作,然后整数右移一位,继续&1,统计得数为1的次数,但是我们发现,当整数为负数时,会出现死循环,因为负数右移时,在最高位补得是1;

因此,我们可以将整数的二进制每一位按位&1操作,然后将1左移一位,&操作后值不为0,count++。

2. 方法二:我们可以循坏进行n&(n-1)操作,当n&(n-1) = 0 时,退出循环。因为我们发现,每进行一次n&(n-1)操作,该二进制数排除了一个1,所以我们可以不停的n & (n-1),直到n == 0000 0000,排除结束。

【迎战蓝桥】 算法·每日一题(详解+多解)-- day5_第3张图片

方法一:代码如下: 

    // 错解
    // 从n的2进制形式的最右边开始判断是不是1
    // 可能陷入死循环的解法
    // 因为负数右移时,在最高位补得是1
    public static int NumberOf1_1(int n) {
        int count = 0;
        while (n != 0){
            if((n & 1) == 1){
                count ++;
            }
            // 把n的2进制形式往右推一位
            n = n >> 1;
        }
        return count;
    }

    // 方法一:
    // 和错解类似,只是我们现在将1左移一位
    public static int NumberOf1_2(int n) {
        int count = 0;
        int flag = 1;
        while (flag != 0){
            if((n & flag) != 0){
                count ++;
            }
            flag = flag << 1;
        }
        return count;
    }

方法二:代码如下:  

    // 方法二:
    // 例:    1000 1010   (n)
    //        1000 1001   (n-1)
    //   &之后 1000 1000   排除了一个1
    // 所以我们可以不停的n & (n-1),直到n == 0000 0000,排除结束
    public static int NumberOf1_3(int n) {
        int count = 0;
        while (n != 0){
            n = n & (n - 1);
            count++;
        }
        return count;
    }

3. 替换空格

描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

解题思路:

1. 方法一:我们可以设置一个空字符串ret,然后遍历题中字符串,当遇到字符为空时ret+="20%",其余ret += s.charAt(i),得到新字符串ret ,return ret 即可。

2. 方法二:我们也可以先统计空字符的个数,然后设置新字符串长度,然后从后往前遍历题中字符串,当遇到字符为空时,分别倒置插入字符'0' '2' '%',其余字符倒置插入即可

方法一:代码如下:  

    // 方法一:
    public static String replaceSpace1(StringBuffer str) {
        String s = str.toString();
        String ret = "";
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(c == ' '){
                ret +="%20";
            }else {
                ret += c;
            }
        }
        return ret;
    }

方法二:代码如下:  

    // 方法二:
    public static String replaceSpace(StringBuffer str) {
        // 找出空格数
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if(str.charAt(i) == ' '){
                count++;
            }
        }

        int old_end = str.length() - 1;
        // 设置新字符串长度
        str.setLength(str.length() + count*2);
        int new_end = str.length() - 1;

        while (old_end >= 0 && new_end >= 0){
            // 填数
            if(str.charAt(old_end) == ' '){
                str.setCharAt(new_end--, '0');
                str.setCharAt(new_end--, '2');
                str.setCharAt(new_end--, '%');
                old_end--;
            }else {
                // 不为空 则平移
                str.setCharAt(new_end--,str.charAt(old_end));
                old_end--;
            }
        }
        return str.toString();
    }

你可能感兴趣的:(蓝桥杯·算法,java,开发语言,算法)