Leetcode169.多数元素(4种解法)

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/majority-element

法1:取巧
由于题目条件说明给定的数组总是存在多数元素,因此排序之后,打印nums[nums.length/2]位置的元素必定是多数元素
执行用时:2ms,在所有Java提交中击败了62.65%的用户
内存消耗:44.5MB,在所有Java提交中击败了13.05%的用户
法2:
使用map,每次加入map之后查询是否超过nums.length/2
执行用时:11ms,在所有Java提交中击败了25.71%的用户
内存消耗:43.6MB,在所有Java提交中击败了85.35%的用户
法3:摩尔投票
两两抵消的思想,由于总长度是一定的,那么不同的数字两两抵消,最后剩下的一定是个数大于总长度一半的。
具体做法:遍历数组,从头开始两两比较,并事先设置一个计算器count,如果两个数字相同,count+1,
若不同则-1
局限性:这种方法其实只能求出数组中个数最多的元素,但由于题目条件说明给定的数组总是存在个数大
于nums.length/2的元素,因此本题中摩尔投票法适用
执行用时:1ms,在所有Java提交中击败了99.97%的用户
内存消耗:44.4MB,在所有Java提交中击败了19.94%的用户

 法1:取巧
由于题目条件说明给定的数组总是存在多数元素,因此排序之后,打印nums[nums.length/2]位置的元素必定是多数元素
执行用时:2ms,在所有Java提交中击败了62.65%的用户
内存消耗:44.5MB,在所有Java提交中击败了13.05%的用户
法2:使用map,每次加入map之后查询是否超过nums.length/2
执行用时:11ms,在所有Java提交中击败了25.71%的用户
内存消耗:43.6MB,在所有Java提交中击败了85.35%的用户
法3:摩尔投票
两两抵消的思想,由于总长度是一定的,那么不同的数字两两抵消,最后剩下的一定是个数大于总长度一半的。
具体做法:遍历数组,从头开始两两比较,并事先设置一个计算器count,如果两个数字相同,count+1,若不同则-1。

局限性:这种方法其实只能求出数组中个数最多的元素,但由于题目条件说明给定的数组总是存在个数大于nums.length/2的元素,因此本题中摩尔投票法适用。
执行用时:1ms,在所有Java提交中击败了99.97%的用户
内存消耗:44.4MB,在所有Java提交中击败了19.94%的用户

 摩尔投票法动图(图片来源:公众号“算法无遗策“):


法4:位运算
首先预设整型变量x为0,由于java的整型变量是32位的,就可以根据后面的判断把应该是1的位置置1,其余还是0,转为十进制就是要求的多数元素。
判断某一位是否为1方法:先依次遍历32位,再依次遍历数组元素,看数组中的元素在某一位上是否为1,如果在某一位上有一半以上的元素都是1,那么这个多数元素在这一位上肯定就是1。全部遍历完之后,判断为1的位置就是1,其余位置就是初始值0,转为十进制就是要求的多数元素。

执行用时:9ms,在所有Java提交中击败了26.31%的用户
内存消耗:44.2MB,在所有Java提交中击败了55.12%的用户

package 数组;

import java.util.Arrays;
import java.util.HashMap;

public class 多数元素_169 {
    /*
    法1:取巧
    由于题目条件说明给定的数组总是存在多数元素,因此排序之后,打印nums[nums.length/2]位置的元素必定是多数元素
    执行用时:2ms,在所有Java提交中击败了62.65%的用户
    内存消耗:44.5MB,在所有Java提交中击败了13.05%的用户
     */
    public static int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
    /*
    法2:
    使用map,每次加入map之后查询是否超过nums.length/2
    执行用时:11ms,在所有Java提交中击败了25.71%的用户
    内存消耗:43.6MB,在所有Java提交中击败了85.35%的用户
     */
    public static int majorityElement2(int[] nums) {
        HashMap integerIntegerHashMap = new HashMap<>();
        int x=0;
        for (int i = 0; i < nums.length; i++) {
            x=integerIntegerHashMap.getOrDefault(nums[i],0)+1;
            if (x> nums.length/2)
                return nums[i];
            integerIntegerHashMap.put(nums[i], x);
        }
        return 0;
    }
    /*
    法3:摩尔投票
    两两抵消的思想,由于总长度是一定的,那么不同的数字两两抵消,最后剩下的一定是个数大于总长度一半的。
    具体做法:遍历数组,从头开始两两比较,并事先设置一个计算器count,如果两个数字相同,count+1,若不同则-1
    局限性:这种方法其实只能求出数组中个数最多的元素,但由于题目条件说明给定的数组总是存在个数大于nums.length/2的元素,因此本题中摩尔投票法适用
    执行用时:1ms,在所有Java提交中击败了99.97%的用户
    内存消耗:44.4MB,在所有Java提交中击败了19.94%的用户
     */
    public static int majorityElement3(int[] nums){
        //x是最后要返回的数字,暂定为数组第一个数字,count是计数器
        int x=nums[0],count=0;
        for (int i = 0; i < nums.length; i++) {
            //如果两个数字相同,count++
            if (x==nums[i])
                count++;
            //若不同则-1
            else count--;
            //如果计数器为0(索引为i之前的数字全部抵消完),重新设置count为1,并把x设为当前数字
            if (count==0){
                count=1;
                x=nums[i];
            }
        }
        return x;
    }
    /*
    法4:位运算
    首先预设整型变量x为0,由于java的整型变量是32位的,就可以根据后面的判断把应该是1的位置置1,其余还是0,转为十进制就是要求的多数元素。
    判断某一位是否为1方法:先依次遍历32位,再依次遍历数组元素,看数组中的元素在某一位上是否为1,如果在某一位上有一半以上的元素都是1,那么这
    个多数元素在这一位上肯定就是1。全部遍历完之后,判断为1的位置就是1,其余位置就是初始值0,转为十进制就是要求的多数元素
    执行用时:9ms,在所有Java提交中击败了26.31%的用户
    内存消耗:44.2MB,在所有Java提交中击败了55.12%的用户
     */
    public static int majorityElement4(int[] nums){
        //x是预设值(也是最后的返回值),temp=1通过&操作判断某一位是否为1(&操作同为1才是1)
        int x=0,temp=1;
        //遍历32位
        for (int i = 0; i < 32; i++) {
            //每次循环计数器count置0
            int count=0;
            //循环数组元素
            for (int j = 0; j < nums.length; j++) {
                //&操作判断这个元素在这一位上是否是1
                //依靠temp中唯一的1与数组中元素在这一位上的数字做&操作来判断这个数组元素在这一位上是否为1
                if ((nums[j]&temp)==temp)
                    //如果是1,count++
                    count++;
                //如果在某一位上有一半以上的元素都是1,那么这个多数元素在这一位上肯定就是1
                if (count> nums.length/2){
                    //预设值x与temp做|(或)操作,只要有一个是1结果就是1,此处x初值都是0,temp在这一位上是1,|操作之后x在这一位上就是1
                    x|=temp;
                    //有一半以上的元素都是1,提前结束
                    break;
                }
            }
            //位的左移通过每次循环结束后temp<<=1实现,每次左移一位,temp对应二进制数中唯一的1就左移一位,依靠这个1与数组中元素在这一位上的数字做&操作来判断这个数组元素在这一位上是否为1
            temp<<=1;
        }
        return x;
    }
    public static void main(String[] args) {
        int []a={3,3,4};
        System.out.println(majorityElement4(a));
    }
}

你可能感兴趣的:(Leetcode算法面试题汇总,java,intellij-idea,算法,数据结构,idea)