剑指Offer数字数组相关算法(一)

前言

本系列博客的刷题顺序根据牛客网的这篇文章来安排,附上自己整理的解题思路。
剑指 Offer 总结 - leetcode 剑指offer系列


剑指 Offer 03. 数组中重复的数字

题目

在这里插入图片描述

解析

利用HashSet集合元素不重复的特性

class Solution {
    public int findRepeatNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();

        for (int num : nums) {
            if (set.contains(num)) {
                return num;
            } else {
                set.add(num);
            }
        }
        return -1;
    }
}


剑指 Offer 04. 二维数组中的查找

题目

在这里插入图片描述

解析

以第一行最后一列位置的数开始,当目标数小于这个位置的数,列数减一;当目标数大于这个数,行数加一;相等就返回true

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int rows = matrix.length, columns = matrix[0].length;
        int row = 0, column = columns - 1;
        while (row < rows && column >= 0) {
            int num = matrix[row][column];
            if (num > target) {
                column--;
                continue;
            } else if (num < target) {
                row++;
                continue;
            } else {
                return true;
            }
        }
        return false;
    }
}

剑指 Offer 11. 旋转数组的最小数字

题目

在这里插入图片描述

解析

傻瓜式……

class Solution {
    public int minArray(int[] numbers) {
        int minValue = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            if (minValue > numbers[i]) {
                minValue = numbers[i];
            }
        }
        return minValue;
    }
}

剑指 Offer 14- I. 剪绳子

题目

在这里插入图片描述

解析

当绳子大于4时,尽可能的把它截成数字为3的小段,乘积最大。
在这里插入图片描述

class Solution {
        public int cuttingRope(int n) {
            if(n < 4) return n - 1;
            int res = 1;
            while (n > 4) {
                res *= 3;
                n -= 3;
            }
            return res * n;


        }

    }

剑指 Offer 14- II. 剪绳子 II

题目

在这里插入图片描述

解析

和上一个一样,结果取余

class Solution {
    public int cuttingRope(int n) {

        if (n < 4) {
            return n - 1;
        }

        Long res = 1L;
        int k = (int) 1e9+7;

        while (n > 4) {
            res = res * 3 % k;
            n -= 3;
        }

        return (int) (res * n % k);
    }
}

剑指 Offer 17. 打印从 1 到最大的 n 位数

题目

在这里插入图片描述

解析

首先得出最大的数k,然后指定一个k大小的数组来存放这个数组即可

class Solution {
    public int[] printNumbers(int n) {

        int k = 1;
        for (int i = 1; i <= n; i++) {
            k *= 10;
        }

        k -= 1;

        int[] res = new int[k];
        for (int i = 0; i < res.length; i++) {
            res[i] = i + 1;
        }

        return res;
    }
}

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

题目

在这里插入图片描述

解析

类似于快排的思路,这里指定数组开始和最后的索引,从前往后遍历数组,同时从后往前遍历。当遍历到的后面的数为奇数,和当前left索引即前面的数交换位置;当遍历到的前面的数是偶数,和当前right索引即后面的数交换位置。左右索引重合退出遍历。

class Solution {
    public int[] exchange(int[] nums) {

        int left = 0;
        int right = nums.length - 1;

        while (left < right) {
            while (left < right && nums[right] % 2 == 0) {
                right--;
            }
            while (left < right && nums[left] % 2 == 1) {
                left++;
            }
            if (left < right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
            }
        }
        return nums;


    }
}

剑指 Offer 39. 数组中出现次数超过一半的数字

题目

在这里插入图片描述

解析

投票法,简单来讲,遍历数组中的数,为每一个遍历到的数投一票(count + 1),当遍历到同样的数时,再投一票,不然减一票。最后的x必然是数组中次数超过一半的数

class Solution {
    public int majorityElement(int[] nums) {
        int count = 0, x = 0;
        for (int num : nums) {
            if (count == 0) {
                x = num;
            }
            count += x == num ? 1 : -1;
        }
        return x;
    }
}

剑指 Offer 40. 最小的 k 个数

题目

在这里插入图片描述

解析

快排,然后copyOf

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {

        quickSort(arr, 0, arr.length - 1);
        return Arrays.copyOf(arr, k);


    }

    private void quickSort(int[] arr, int l, int r) {
        // 子数组长度为 1 时终止递归
        if (l >= r) return;
        // 哨兵划分操作(以 arr[l] 作为基准数)
        int i = l, j = r;
        while (i < j) {
            while (i < j && arr[j] >= arr[l]) j--;
            while (i < j && arr[i] <= arr[l]) i++;
            swap(arr, i, j);
        }
        swap(arr, i, l);
        // 递归左(右)子数组执行哨兵划分
        quickSort(arr, l, i - 1);
        quickSort(arr, i + 1, r);
    }
    private void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


}

剑指 Offer 41. 数据流中的中位数

题目

在这里插入图片描述

解析

构建大顶堆和小顶堆,大顶堆存放较小的一半数据,小顶堆存放较大的一半数据。

首先把它们当成队列来处理(poll方法)。A堆即小顶堆构建完成,把最小的数据给B堆;B堆即大顶堆构建完成,把最大的数给A堆。

最后,当遍历数组完成,这时把这两个堆当成栈处理(peek方法)当A,B堆size不同,弹出A堆堆顶数作为中位数,否则两个堆都弹出堆顶数。相加除以二。

class MedianFinder {
    Queue<Integer> A, B;
    public MedianFinder() {
        A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
        B = new PriorityQueue<>((x, y) -> (y - x)); // 大顶堆,保存较小的一半
    }
    public void addNum(int num) {
        if(A.size() != B.size()) {
            A.add(num);
            B.add(A.poll());
        } else {
            B.add(num);
            A.add(B.poll());
        }
    }
    public double findMedian() {
        return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
    }
}

剑指 Offer 43. 1 ~ n 整数中 1 出现的次数

题目

在这里插入图片描述

解析

在这里插入图片描述

class Solution {
    public int countDigitOne(int n) {
        return f(n);
    }

    private int f(int n) {
        if (n <= 0) {
            return 0;
        }
        String s = String.valueOf(n);
        int high = s.charAt(0) - '0';
        int pow = (int) Math.pow(10, s.length() - 1);
        int low = n - high * pow;

        if (high == 1) {
            return f(pow - 1) + 1 + low + f(low);
        } else {
            return pow + high * f(pow - 1) + f(low);
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值