剑指 offer——其他类

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

题意:面试题43. 1~n整数中1出现的次数
思路:找规律。每一位digit上的1出现的次数只与:它前面的数字high、它后面的数字low、当前位的因数\(10^{digit}\)相关。
分情况讨论:
1)第i位上的数字 == 0。1~n中,这一位上1出现的次数只与高位有关。(例如2304的第3位为0,1~2304中第3位为1的情况有001x ~ 221x,一共23 * 100个, 即high * \(10^{digit}\)个)
2)第i位上的数字 == 1。1~n中,这一位上1出现的次数和高低位都有关系。(例如2314中第3位为1,1~2314中第3位为1的情况有001x ~ 221x,2310 ~ 2314,一共high * \(10^{digit}\) + low + 1个)
3)第i位上的数字 > 1。1~n中,这一位上1出现的次数只与高位有关。(例如2304中的第2位为3,1~2304中第2位为1的情况有01xx~21xx,一共(high + 1) * \(10^{digit}\)个)

class Solution {
    public int countDigitOne(int n) {
        int count = 0;
        int high = n / 10;
        int low = 0;
        int cur = n % 10;
        int digit = 1;
        while (high != 0 || cur != 0) {
            if (cur == 0) {
                count += high * digit;
            } else if (cur == 1) {
                count += high * digit + (low + 1);
            } else {
                count += (high + 1) * digit;
            }
            low += cur * digit;
            digit *= 10;
            cur = high % 10;
            high /= 10;
        }
        return count;
    }
}

44. 数字序列中某一位的数字

题意:面试题44. 数字序列中某一位的数字
思路:先判断给定的n是否在i位的范围之内(比如n在10以内,是在1位数的范围内;超过10又在100以内,是在2位数的范围内……以此类推),然后计算n是i位数的第几个数的第几位。

class Solution {
    List<Integer> list = Arrays.asList(0, 10, 100, 1_000, 10_000,
    100_000, 1_000_000, 10_000_000, 100_000_000, 1_000_000_000);

    public int findNthDigit(int n) {
        int bit = 1;
        long len;
        while (n > 0) {
            len = list.get(bit) - list.get(bit - 1);
            if (len * bit >= n) {
                break;
            }
            n -= len * bit;
            bit ++;
        }
        int num = list.get(bit - 1) + n / bit;
        return String.valueOf(num).charAt(n % bit) - '0';
    }
}

45. 把数组排成最小的数

题意:面试题45. 把数组排成最小的数
思路:自定义比较器。【对于两个数字,不能简单的将较小的数字放在前面,大的数字放在后面(如2和12,最小的数应该是122,而不是212)。】正确的做法是比较两个数字组合起来的字串,将组合后字串字典序小的放前面。

class Solution {
    public String minNumber(int[] nums) {
        Integer[] tmp = new Integer[nums.length];
        for (int i = 0; i < tmp.length; i++) {
            tmp[i] = nums[i];
        }
        Arrays.sort(tmp, (a, b) -> {
            String s1 = String.valueOf(a) + String.valueOf(b);
            String s2 = String.valueOf(b) + String.valueOf(a);
            return s1.compareTo(s2);
        });
        StringBuilder sb = new StringBuilder();
        for (int i : tmp) {
            sb.append(i);
        }
        return sb.toString();
    }
}

62. 圆圈中最后剩下的数字

题意:面试题62. 圆圈中最后剩下的数字
思路:递归。如果只有一个数字,剩下的就是第一个位置的数字,返回即可(终止条件)。如果有n-1个数字,删除的数字是第k个数字,长度为n的时候要从第k个位置开始向后数m个位置。因此递推式为:f(n, m) = (f(n - 1, m) + m) % n。

class Solution {
    public int lastRemaining(int n, int m) {
        if (n == 1) {
            return 0;
        }
        int left = lastRemaining(n - 1, m);
        return (m + left) % n;
    }
}

64. 求1+2+…+n

题意:面试题64. 求1+2+…+n
思路:使用运算符短路特性+递归。

class Solution {
    public int sumNums(int n) {
        int res = n;
        boolean flag = (n > 0) && (res += sumNums(n - 1)) != 0;
        return res;
    }
}
posted @ 2020-07-19 20:01  MoonLeo2017  阅读(78)  评论(0编辑  收藏  举报