思路
题目分析
- 题目给出一串字符串,包含数字和大写英文字母
- 题目要求我们找出其中连续的最大的一组十六进制字符串
- 并最终返回其十进制的结果
- 方法一使用指针的思路,从前往后按照顺序访问字符串,将首指针和尾指针分别指向一组合法的16进制子字符串,然后计算其10进制值,下一轮继续用首尾指针读取一个16进制子字符串,转换成10进制值,并以此循环迭代计算出所有的10进制值,记录返回最大值即可
- 方法二使用贪心思路,优化方法一中获取子字符串的部分,贪心地选择最大的区间存储到返回值中,贪心的最大距离就是遇到非法16进制字符的时候。最终返回16进制最大值即可。
方法一:双指针
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param s string字符串 * @return int整型 */ bool legal(char c) { // 判断字符是否是16进制合法 return (c <= '9' && c >= '0') || (c >= 'A' && c <= 'F'); } int c2i(char c) { // 将16进制字符转换成10进制数 if(c >= 'A' && c <= 'F') return c - 'A' + 10; return c - '0'; } int hex2dec(string s) { // 将16进制字符串转换成10进制数字 int n = 0; for(int i = 0; i < s.size(); i++) { n += c2i(s[i]) * pow(16, s.size() -i -1); } return n; } int solve(string s) { // write code here int res = 0; int n = s.size(); for(int i = 0, j = 0; i < n; i++) { if(legal(s[i]) && s[i] != '0') { // 左指针通过循环一直找到合法的16进制子字符串的开头 for(j = i; j < n; j++) { if(!legal(s[j])) { // 右指针通过循环找到合法16进制子字符串的末尾 break; } } res = max(res, hex2dec(s.substr(i, j-i))); //返回当前双指针限制区域内的16进制子字符串的10进制值,维护最大值 i = j; // 迭代从下一处继续开始 } } return res; // 返回最大值 } };
复杂度分析
- 时间复杂度:,虽然看起来有双重循环,但是对字符串只按序访问了一次
- 空间复杂度:,无额外空间申请
方法二:贪心
class Solution { public: /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param s string字符串 * @return int整型 */ int hex2dec(char c) { // 将表示16进制的字符转换为十进制的数字 return c >= 'A' ? c - 'A' + 10 : c - '0'; } int solve(string s) { // write code here int sum = 0; int mx = 0; for(int i = 0; i < s.size(); i++) { if(s[i] > 'F') { // 如果碰到非16进制的字符,则认为要在新的起点处重新计算一组sum值 mx = max(mx, sum); // 维护最大值 sum = 0; // 重置sum值,准备计算新的一组十六进制数的值 continue; } int num = hex2dec(s[i]); // 将当前访问字符转换为16进制 sum = sum * 16 + num; // 通过多轮次循环来计算16进制数 } return mx; } };
复杂度分析
- 时间复杂度:,一重循环的时间开销
- 空间复杂度:,无额外空间申请