leetcode算法—至少有一位重复的数字

原题链接:https://leetcode.cn/problems/numbers-with-repeated-digits/

使用数位dp来做

func numDupDigitsAtMostN(n int) int {
    s := strconv.Itoa(n)
    m := len(s)
    memo := make([][1 << 10]int, m) 

    for i := range memo {
        for j := range memo[i] {
           memo[i][j] = -1 
        } 
    }  
    for i := range memo {
        for j := range memo[i] {
            memo[i][j] = -1
        }
    }

    // i表示当前选择的位置,mask表示当前已经选择过的数
    // isLimit表示当前位置的数是否受限
    // isNumber表示上一个位置是否跳过
    var dfs func(i, mask int,isLimit, isNumber bool) int
    dfs = func(i, mask int, isLimit, isNumber bool) int {
        if i == m {
            if isNumber {
                return 1
            }
            return 0
        }
        
        // 必须判断isLimit和isNumber是因为
        // 当!isNumber或者isLimit时, 是不会重复执行到的,所以无需记化
        // 只有!isLimit和isNumber才需要记忆化
        // 注意其实isLimit或isNumber的成立隐含着前面所有的字符都是isLimit和isNumber
        if !isLimit && isNumber && memo[i][mask] != -1  {
            return memo[i][mask]
        }
        
        res := 0
        if !isNumber {
            res += dfs(i+1, mask, false, false)    
        }

        low := 1 
        if isNumber {
            low = 0
        }
        high := 9
        if isLimit {
            high = int(s[i] - '0')
        }

        
        for j := low; j <= high; j ++ {
            // 如果j在mask中,则不选择
            if (mask >> j) & 1 != 1 {
                res += dfs(i+1, mask | (1 << j), isLimit&&(j == high), true)    
            }
        }

        if isNumber && !isLimit {
            memo[i][mask] = res
        }

        return res
    }
    
    return n - dfs(0, 0, true, false)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值