算法通关村第二关——继续讨论数组问题

算法通关村第二关——继续讨论数组问题

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

题目:剑指offer,找出数组中超过一半的数字

思路:总共有三种思路,

  1. 排序算法,取中位数(不够优化,具体解法略)
  2. 利用map进行计数
  3. 利用出现次数,如果下一个数字和当前数字相同则+1,不同则-1,为0则开始下一个数字的统计(累加法)

解法:

  1. map计数法

        /**
         * 数组中出现次数超过一半的数字
         * 方法一:排序算法,取中位数
         * 方法二:利用map进行计数
         * @param array
         * @return
         */
        public int moreThanHalfNum(int[] array) {
            //1.利用map进行计数(方法二)
            int length = array.length;
            HashMap<Integer, Integer> countMap = new HashMap<>(12);
            for (int i = 0; i < array.length; i++) {
                countMap.put(array[i],countMap.getOrDefault(array[i],0)+1);
                if (countMap.get(array[i])>length/2){
                    return array[i];
                }
            }
            return 0;
        }
    
  2. 累加法

        /**
         * 数组中出现次数超过一半的数字
         * 方法一:排序算法,取中位数
         * 方法二:利用map进行计数
         * 方法三:利用出现次数,如果下一个数字和当前数字相同则+1,不同则-1,为0则开始下一个数字的统计(累加法)
         * @param array
         * @return
         */
        public int moreThanHalfNum2(int[] array) {
            //1.利用方法三累加法计算
            int count = 0;
            Integer candidate = 0;
            for (int num : array) {
                if (count == 0) {
                    candidate = num;
                }
                count += (num == candidate) ? 1 : -1;
            }
            return candidate;
        }
    

数组中只出现一次的数字

题目:leetCode:136

思路:有多种思路,

  1. 使用set集合不重复的特点,最后留在set集合当中的就是只出现一次的数字
  2. 利用异或的位运算去解决

解法:

  1. set集合

        /**
         * 只出现一次数字
         * 1.方法一使用set集合
         * 2.方法二
         * @param nums
         * @return
         */
        public int singleNumber(int[] nums) {
            //使用set集合
            HashSet<Integer> integerHashSet = new HashSet<>();
            for (int num : nums) {
                if (integerHashSet.contains(num)){
                    integerHashSet.remove(num);
                }else {
                    integerHashSet.add(num);
                }
            }
            for (Integer i : integerHashSet) {
                return i;
            }
            return 0;
        }
    
  2. 利用异或运算

        /**
         * 只出现一次数字
         * 1.方法一使用set集合
         * 2.方法二 使用位运算
         * @param nums
         * @return
         */
        public int singleNumber(int[] nums) {
            //使用位进行异或运算
            int i = 0;
            //遍历数组进行位运算
            for (int num : nums) {
                i = i^num;
            }
            return i;
        }
    

数组中只出现一次的数字2

题目:leetCode:137,现在其他数字均会重复3次,只有一个数字会重复一次

思路:对于该题目有多种思路

  1. 常规,利用map来进行计数
  2. 利用有限状态自动机+位运算来解决,因为重复数字转换成二进制会在每一位上出现 3次或者是3的倍数(多个重复数字,)所以只要把每一位上求3的余算出,那 就是对应只出现一次的数字

解法:

  1. 利用map

        /**
         * 只出现一次数字
         * 1.方法一使用map集合
         * 2.方法二 使用位运算
         * @param nums
         * @return
         */
        public int singleNumber(int[] nums) {
            //使用map集合
            HashMap<Integer, Integer> map = new HashMap<>(12);
            for (int num : nums) {
                int i = map.getOrDefault(num, 0) + 1;
                map.put(num,i);
            }
            //循环遍历,找出map中等于1的
            for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
                if (entry.getValue()==1){
                    return entry.getKey();
                }
            }
            return 0;
        }
    
  2. 利用异或+与进行位运算(以后在研究)

    class Solution {
        public int singleNumber(int[] nums) {
            int ones = 0, twos = 0;
            for(int num : nums){
                ones = ones ^ num & ~twos;
                twos = twos ^ num & ~ones;
            }
            return ones;
        }
    }
    //具体解题过程参考:https://leetcode.cn/problems/single-number-ii/solutions/8944/single-number-ii-mo-ni-san-jin-zhi-fa-by-jin407891/?envType=list&envId=Bln79jJg
    

颜色分类问题(荷兰国旗问题)

题目:leetCdoe:75

思路:

  1. 基于冒泡排序的双指针(快慢指针),先处理0的位置,在处理1的位置,总共遍历两次
  2. 只要求一次遍历,可以利用三指针的思路,一个指针是0的代表,一个是1的代表,一个是2的代表

解法:

  1. 基于冒泡排序的双指针(快慢指针)

        /**
         * 方法一:基于冒泡排序的双指针(快慢指针)
         * 方法二:
         * @param nums
         */
        public void sortColors(int[] nums) {
            //基于冒泡排序双指针
            int slow = 0;
            //1.第一次排序,把0交换到最前
            for (int fast = 0; fast < nums.length; fast++) {
                if (nums[fast]==0){
                    int tmp = nums[fast];
                    nums[fast] = nums[slow];
                    nums[slow] =tmp;
                    slow++;
                }
            }
            for (int fast = slow; fast < nums.length; fast++) {
                if (nums[fast]==1){
                    int tmp = nums[fast];
                    nums[fast] = nums[slow];
                    nums[slow] =tmp;
                    slow++;
                }
            }
        }
    
  2. 基于三指针的排序算法(还有一种类似于双指针的一次循环)

        /**
         * 方法一:基于冒泡排序的双指针(快慢指针)
         * 方法二:用三个指针解决一次遍历
         * @param nums
         */
        public void sortColors(int[] nums) {
            //基于三个指针解决一次遍历
            int left = 0;
            int right = nums.length-1;
            int index = 0;
            //1.第一次排序,把0交换到最前
            while ( index<=right) {
                //先处理2的情况
                if (nums[index]==0){
                    swap(nums,index++,left++);
                }else if (nums[index]==2&&index!=right){
                    swap(nums,index,right--);
                }else {
                    index++;
                }
            }
        }
        private void swap(int[]nums,int i,int j){
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值