[LeetCode] 91. Decode Ways

原题链接:https://leetcode.com/problems/decode-ways/

1. 题目介绍

A message containing letters from A-Z is being encoded to numbers using the following mapping:

‘A’ -> 1
‘B’ -> 2

‘Z’ -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.

有一种编码方式是用数组代表字母。1代表A,2代表B······26代表Z。
给出一个非空字符串,字符串只由数字组成,由多少种方法去破译它。

Example 1:

Input: “12”
Output: 2
Explanation: It could be decoded as “AB” (1 2) or “L” (12).

Example 2:

Input: “226”
Output: 3
Explanation: It could be decoded as “BZ” (2 26), “VF” (22 6), or “BBF” (2 2 6).

2. 解题思路

2.1 动态规划法

可以考虑用动态规划法来解决此问题。

对于字符串的每一个数字来说,有两种破译的方式

  1. 当前数字本身代表一个字母,比如1就代表A,2就代表B,6就代表F。这种破译方式要求数字不等于0。
  2. 当前数字和前一个数字共同代表一个字母,当前数字只是个位。比如字符串是26,这个6是当前数字,它可以和前面的2共同代表字母Z。这种破译方式要求前一个数字是1,或者是2;并且当前一个数字是2时,当前数字必须小于等于6。

因此我们可以构造一个一维数组dp[],dp的长度和字符串的字符数相同。dp[ i ]代表截止第 i 个字符,破译的方式有多少种。

若第 i 个数字采用上面第 1 种破译方式,相当于在已经破译得到的字符串的最后再加上一个字母,因此dp[ i ] = dp[ i -1 ]

若第 i 个数字采用上面第 2 种破译方式,相当于在前面第i-2个字符所得到的字符串的最后再加上一个字母,因此dp[ i ] = dp[ i -2 ]

对于每一个数字,都要考虑两种破译方式,这两种破译方式得到的结果不冲突,都要算在内。

实现代码

class Solution {
    public int numDecodings(String s) {
        int length = s.length();
        if(length ==0) {
        	return 0;
        }
        
        if(s.charAt(0) == '0') {
        	return 0;
        	//如果字符串的第一个字符是“0”,那么无法破译,返回0
        }
        
        if(length ==1) {
        	return 1;
        }
     
        int [] dp = new int [length];
        dp[0] = 1;
        
        //只考虑个位的情况
        if(s.charAt(1) != '0') {
    		dp[1] += dp[0];
    	}
        //十位为1,个位随意的情况
    	if(s.charAt(0) == '1'  ) {
    		dp[1] += 1;
    	}
    	
    	//十位为2,个位小于等于6的情况
    	if(s.charAt(0) =='2' && s.charAt(1) <='6' ) {
    		dp[1] += 1;
    	}
        
        for(int i = 2;i<length;i++) {
        	char now = s.charAt(i);
        	char before = s.charAt(i-1);
        	//只考虑个位的情况
        	if(now != '0') {
        		dp[i] += dp[i-1];
        	}
        	//十位为1,个位随意的情况
        	if(before == '1'  ) {
        		dp[i] += dp[i-2];
        	}
        	//十位为2,个位小于等于6的情况
        	if(before == '2' && now <='6' ) {
        		dp[i] += dp[i-2];
        	}
        }   
        return dp[length-1];
    }
}

2.2 进一步改进:抛弃一维数组

可以看到每次更新dp[ i ] 只用到了dp[ i-2 ]和dp[ i-1 ],没有用到dp数组的其他值,因此可以使用三个整数来代替dp数组,节省空间。

实现代码

class Solution {
    public int numDecodings(String s) {
        int length = s.length();
        if(length ==0) {
        	return 0;
        }
        
        if(s.charAt(0) == '0') {
        	return 0;
        	//如果字符串的第一个字符是“0”,那么无法破译,返回0
        }
        
        if(length ==1) {
        	return 1;
        }
     
        int a,b,c;
        a = 1;
        b = 0;
        c = 0;
        
        //只考虑个位的情况
        if(s.charAt(1) != '0') {
    		b += a;
    	}
        //十位为1,个位随意的情况
    	if(s.charAt(0) == '1'  ) {
    		b += 1;
    	}
    	
    	//十位为2,个位小于等于6的情况
    	if(s.charAt(0) =='2' && s.charAt(1) <='6' ) {
    		b += 1;
    	}
               
        for(int i = 2;i<length;i++) {
        	char now = s.charAt(i);
        	char before = s.charAt(i-1);
        	//只考虑个位的情况
        	if(now != '0') {
        		c += b;
        	}
        	//十位为1,个位随意的情况
        	if(before == '1'  ) {
        		c += a;
        	}
        	//十位为2,个位小于等于6的情况
        	if(before == '2' && now <='6' ) {
        		c += a;
        	} 	
        	a = b;
        	b = c;
        	c = 0;
        }     
        return b;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值