给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
我的第一思路是利用递归思想,将问题根据数字数组的长度和前两个数字来划分成子问题:
当长度为0或者1时,递归函数直接返回1,因为此时不会有多余情况了当长度大于2时,要根据前两位数进行划分:
- 若第一个数字为0或者二位数大于25,则此时只有一种情况,即将第一个数字翻译成一个字母,返回后参数是 后n-1个数字串 可能的情况类型个数若二位数<25 ,则可以有两种划分 ,即两个数字作为一个字母,或者一个对应一个字母
显然,递归算法会开辟更多的空间,但时间复杂度较好:
class Solution { public: int translateNum(int num) { vectornums; int n=0; while(num) { nums.insert(nums.begin(),num - (num/10)*10); num = num/10; n++; } return countNum(nums,0,n); } int countNum(vector nums,int a , int n) { if(n < 0) return 0; else if(n == 1 || n == 0) return 1; else { if(nums[a]*10+nums[a+1] > 25 || nums[a]==0 ) return countNum(nums,a+1,n-1); else return countNum(nums,a+1,n-1) + countNum(nums,a+2,n-2); }; } };
本题最好的方法还是动态规划的方法,主要思想如下:
dp[ i ] 表示以i为结尾的数字串的翻译类型个数
转移方程: d p[ i ] = if (i 和 i-1 能组合翻译) dp[ i ] = dp[i-1] + dp[ i - 2]
else : dp[i] = dp [ i-1]
提升性能的两个tips:
- 由于整体顺序是一遍的遍历,因此可以不需要先将数转换为字符串或者一维数组,直接循环取余,自右向左动态规划由于每次运算只涉及dp数组中的第 i i -1 i -2 的元素,因此也不需要开辟dp数组,直接用a b c变量进行代替即可
class Solution { public: int translateNum(int num) { string str = to_string(num); int len = str.size(); if(len < 2) return len; int a,b,c; //代表dp i-2/i-1/i b = 1; a = 1; for(int i = 2;i <= len;i++){ if(str[i-2] == '1' || (str[i-2] == '2' && str[i-1] <= '5')) c = a+b; else c = b; } return dp[len]; } };Q2 最长不含重复字符的子字符串
从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
我的第一种思路,使用集合的数据结构,根据字符串进行递推,dp[ i ]表示以 i 为结尾的最长的不重复子字符串:
当某一字符在当前字符集合已经存在,则清空集合,回溯,构造新的集合,计算dp值当某一字符不存在与当前集合,则加入集合,dp[ i ] = dp[ i-1 ] + 1
缺点:dp和集合 占用空间,回溯浪费大量时间
class Solution { public: int lengthOfLongestSubstring(string s) { setsett; int n = s.length(); if(n <= 1) return n; int dp[n]; dp[0] = 1; sett.insert(s[0]); int max = 1,j; for(int i=1;i =0;j--) { sett.insert(s[j]); if(s[i] == s[j]) break; } dp[i] = i - j; }else{ dp[i] = dp[i-1] + 1; sett.insert(s[i]); if(dp[i]>max) max = dp[i]; } } return max; } };
根据题解,其实不需要使用集合,在第一种情况中,只需要向左找到第一个相同的元素求差即可,当然也可以用哈希表来存贮有关信息,减少了向左搜索的过程。
class Solution { public: int lengthOfLongestSubstring(string s) { int len = s.size(); if (len == 0) { return 0; } unordered_maphash; //存储每个字符 和 该字符最后出现的位置(每次遍历到相同的字符会更新下标) int max_len = 0, sub_len = 0; for(int right=0;right 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)