LeetCode 248. Strobogrammatic Number III

20 篇文章 0 订阅
20 篇文章 0 订阅

原题网址:https://leetcode.com/problems/strobogrammatic-number-iii/

A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).

Write a function to count the total strobogrammatic numbers that exist in the range of low <= num <= high.

For example,
Given low = "50", high = "100", return 3. Because 69, 88, and 96 are three strobogrammatic numbers.

Note:
Because the range might be a large number, the low and high numbers are represented as string.

思路:深度优先搜索。注意当low的位数和high的位数不相等的时候如何处理,以及如何保证深度优先的生成的数字符合要求。

这是一个典型的深度优先搜索题目,我想在字符数值比较等地方提升搜索效率,于是写得比较恶心。

public class Solution {
    private char[] pair = {'0','1','6','8','9'};
    private char[] rotated = {'0', '1', ' ', ' ', ' ', ' ', '9', ' ', '8', '6'};
    private char[] self = {'0','1','8'};
    private int find(char[] low, char[] high, boolean min, boolean max, char[] buf, int step) {
        if (step == buf.length) return 1;
        int count = 0;
        if ((step<<1) == buf.length) {
            // 当位数为偶数,且深度优先过半时
            for(int i=step, j=step-1; i<buf.length; i++, j--) {
                buf[i] = rotated[buf[j]-'0'];
                if (min && buf[i] < low[i]) return 0;
                if (max && buf[i] > high[i]) return 0;
                if (buf[i] > low[i]) min = false;
                if (buf[i] < high[i]) max = false;
            }
            // System.out.printf("found %s\n", new String(buf));
            return 1;
        } else if ((step<<1) == buf.length-1) {
            // 当位数为奇数,且深度优先处于中间数位时
            for(int i=0; i<self.length; i++) {
                boolean nmin = min;
                boolean nmax = max;
                buf[step] = self[i];
                if (min && buf[step] < low[step]) continue;
                if (max && buf[step] > high[step]) continue;
                if (buf[step] > low[step]) nmin = false;
                if (buf[step] < high[step]) nmax = false;
                count += find(low, high, nmin, nmax, buf, step+1);
            }
        } else if ((step<<1) > buf.length) {
            // 当位数为奇数,且深度优先过半时
            for(int i=step, j=step-2; i<buf.length; i++, j--) {
                buf[i] = rotated[buf[j]-'0'];
                if (min && buf[i] < low[i]) return 0;
                if (max && buf[i] > high[i]) return 0;
                if (buf[i] > low[i]) min = false;
                if (buf[i] < high[i]) max = false;
            }
            // System.out.printf("found %s\n", new String(buf));
            return 1;
        } else {
            // 深度优先未过半时
            for(int i=0; i<pair.length; i++) {
                boolean nmin = min;
                boolean nmax = max;
                if (min && pair[i] < low[step]) continue;
                if (max && pair[i] > high[step]) continue;
                if (pair[i] > low[step]) nmin = false;
                if (pair[i] < high[step]) nmax = false;
                buf[step] = pair[i];
                count += find(low, high, nmin, nmax, buf, step+1);
            }
        }
        return count;
    }
    public int strobogrammaticInRange(String low, String high) {
        if (low.length() > high.length()) return 0;
        char[] ha = high.toCharArray();
        char[] la = low.toCharArray();
        int lw = la.length;
        int count = 0;
        do {
            lw = la.length;
            char[] upper = ha;
            if (la.length < upper.length) {
                upper = new char[la.length];
                Arrays.fill(upper, '9');
            }
            // System.out.printf("low=%s, high=%s\n", new String(la), new String(upper));
            count += find(la, upper, true, true, new char[la.length], 0);
            if (lw < ha.length) {
                la = new char[lw+1];
                Arrays.fill(la, '0');
                la[0] = '1';
            }
        } while (lw < ha.length);
        return count;
    }
}


方法二:当涉及到区间[A,B]的计算时,有个重要的思路是将区间转换为[0,B]-[0,A)

另外,深度优先不一定只是深度加1,可以是从两边向中间搜索。

public class Solution {
    private char[][] strobos = {{'0','0'}, {'1','1'}, {'6','9'}, {'8','8'}, {'9','6'}};
    public int strobogrammaticInRange(String low, String high) {
        if (low.length() > high.length()) return 0;
        if (low.length() == high.length() && low.compareTo(high) > 0) return 0;
        return count(high, true) - count(low, false);
    }
    private int count(String high, boolean inclusive) {
        int len = high.length();
        int count = 0;
        for(int i=1; i<len; i++) {
            count += countLen(i, true);
        }
        count += find(new char[len], 0, len-1, high.toCharArray(), inclusive, true);
        return count;
    }
    private int countLen(int len, boolean outside) {
        if (len == 0) return 1;
        if (len == 1) return 3;
        if (outside) return countLen(len-2, false)*4;
        return countLen(len-2, false)*5;
    }
    
    private int find(char[] num, int left, int right, char[] high, boolean inclusive, boolean ceiling) {
        if (left > right) {
            if (!ceiling) return 1;
            int compare = compare(num, high, left, num.length-1);
            if (inclusive && compare <= 0) return 1;
            if (!inclusive && compare < 0) return 1;
            return 0;
        }
        int count = 0;
        for(int i=0; i<strobos.length; i++) {
            if (left == 0 && right != 0 && strobos[i][0] == '0') continue;
            if (left == right && strobos[i][0] != strobos[i][1]) continue;
            if (ceiling && strobos[i][0] > high[left]) continue;
            num[left] = strobos[i][0];
            num[right] = strobos[i][1];
            count += find(num, left + 1, right - 1, high, inclusive, ceiling && num[left] == high[left]);
        }
        return count;
    }
    private int compare(char[] a, char[] b, int from, int to) {
        for(int i=from; i<=to; i++) {
            if (a[i] < b[i]) return -1;
            if (a[i] > b[i]) return 1;
        }
        return 0;
    }
}

参考文章:

https://leetcode.com/discuss/73721/easiest-20ms-94%25-java-solution

https://leetcode.com/discuss/91136/java-0ms-solution-99-5%25

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值