<commit_before>/**
 * Question Link: https://leetcode.com/problems/decode-ways/
 * Primary idea: Dynamic Programming, dp[i] = dp[i - 1] + dp[i - 2], 
 *               determine if current one or two characters are number at first
 * Time Complexity: O(n), Space Complexity: O(n)
 *
 */

class DecodeWays {
    func numDecodings(_ s: String) -> Int {
        let sChars = Array(s.characters), len = sChars.count
        var dp = Array(repeating: 0, count: len + 1)
        dp[0] = 1
        
        guard len >= 1 else {
            return 0
        }
        
        for i in 1...len {
            if isValid(String(sChars[i - 1..<i])) {
                dp[i] += dp[i - 1]
            }
            if i >= 2 && isValid(String(sChars[i - 2..<i])) {
                dp[i] += dp[i - 2]
            }
        }
        
        return dp[len]
    }
    
    private func isValid(_ numStr: String) -> Bool {
        if Array(numStr.characters).first == "0" {
            return false
        }
    
        guard let num = Int(numStr) else {
            return false
        }
        
        return num >= 1 && num <= 26
    }
}<commit_msg>[DP] Update solution to Decode Ways<commit_after>/**
 * Question Link: https://leetcode.com/problems/decode-ways/
 * Primary idea: Dynamic Programming, dp[i] = dp[i - 1] + dp[i - 2], 
 *               determine if current one or two characters are number at first
 * Time Complexity: O(n), Space Complexity: O(n)
 *
 */

class DecodeWays {
    func numDecodings(_ s: String) -> Int {
        let sChars = Array(s)
        var dp = Array(repeating: 0, count: s.count + 1)
        dp[0] = 1
        
        guard s.count >= 1 else {
            return 0
        }
        
        for i in 1...s.count {
            if String(sChars[i - 1..<i]).isValid {
                dp[i] += dp[i - 1]
            }
            if i >= 2 && String(sChars[i - 2..<i]).isValid {
                dp[i] += dp[i - 2]
            }
        }
        
        return dp[s.count]
    }
}

extension String {
    var isValid: Bool {
        if let first = first, first == "0" {
            return false
        }
        
        guard let num = Int(self) else {
            return false
        }
        
        return 0 < num && 26 >= num
    }
}
{'fraction_non_alphanumeric': 0.12918871252204586, 'fraction_numerical': 0.015873015873015872, 'mean_word_length': 1.34400826446281, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 12, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3993581', 'n_tokens_mistral': 766, 'n_tokens_neox': 713, 'n_words': 205}