leetcode解题思路分析(二)8-14题

2024-09-05 05:18
文章标签 leetcode 分析 14 解题 思路

本文主要是介绍leetcode解题思路分析(二)8-14题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  1. 请你来实现一个 atoi 函数,使其能将字符串转换成整数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0。

说明:

假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

不算优秀的做法

class Solution {
public:int myAtoi(string str) {int result = 0;stringstream ss;ss << str;ss >> result;return result;}
};

先排除特殊情况,再逐步检查

class Solution {
public:int myAtoi(string str) {int res = 0;int i = 0;int flag = 1;// 1. 检查空格while (str[i] == ' ') { i++; }// 2. 检查符号if (str[i] == '-') { flag = -1; }if (str[i] == '+' || str[i] == '-') { i++; }// 3. 计算数字while (i < str.size() && isdigit(str[i])) {int r = str[i] - '0';// ------ 4. 处理溢出,这是关键步骤 ------if (res > INT_MAX / 10 || (res == INT_MAX / 10 && r > 7)) { return flag > 0 ? INT_MAX : INT_MIN;}// ------------------------------------res = res * 10 + r;i++;}return flag > 0 ? res : -res;}
};
  1. 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

本题有两种做法:1.转化为字符串再进行检索 2. 获取一半的整数和另一半比较。第二种空间使用更少,更优

class Solution {
public:bool isPalindrome(int x) {// 特殊情况:// 如上所述,当 x < 0 时,x 不是回文数。// 同样地,如果数字的最后一位是 0,为了使该数字为回文,// 则其第一位数字也应该是 0// 只有 0 满足这一属性if(x < 0 || (x % 10 == 0 && x != 0)) {return false;}int revertedNumber = 0;while(x > revertedNumber) {revertedNumber = revertedNumber * 10 + x % 10;x /= 10;}// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。return x == revertedNumber || x == revertedNumber/10;}
};
  1. 正则表达式匹配
    给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

采用从后向前检索的方式进行

class Solution {
public:vector<vector<int> > memo;int dfs(const string& s, const string& p, int i, int j) {if (i == s.size()) return j == p.size() ? 1 : -1;if (j == p.size()) return i == s.size() ? 1 : -1;if (memo[i][j] != 0) return memo[i][j];if (j == p.size() - 1 || p[j + 1] != '*') {if (p[j] == '.' || p[j] == s[i]) {memo[i][j] = dfs(s, p, i + 1, j + 1);return memo[i][j];}} else {if (dfs(s, p, i, j + 2) > 0) {memo[i][j] = 1;return memo[i][j];}if (p[j] == '.' || p[j] == s[i]) {bool t = dfs(s, p, i + 1, j + 2) > 0 || dfs(s, p, i + 1, j) > 0;memo[i][j] = t ? 1 : -1;return memo[i][j];}}memo[i][j] = -1;return memo[i][j];}bool isMatch(string s, string p) {s += '#';p += '#';memo = vector<vector<int> >(s.size(), vector<int>(p.size(), 0));return dfs(s, p, 0, 0) > 0;}
};
  1. 盛最多水的容器
    给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

最简单无脑的做法:直接双层循环:

class Solution {
public:int maxArea(std::vector<int>& height) {int i = 0;int j = 0;int capacity = 0;int size = height.size();while(i < size - 1){j = i + 1;while (j < size){int tmpCap = std::min(height[i], height[j]) * (j - i);if (tmpCap >= capacity){capacity = tmpCap;}j++;}i++;}return capacity;}
};

第二种思路是:形成的区域受限制于较短的那条,同时距离越远则可能的收益越大。因此我们从最左和最右开始检索,移动较短的那端。

    int maxArea(vector<int> &height){int result = 0;int heightSize = int(height.size());int leftIndex = 0;int rightIndex = heightSize - 1;while (leftIndex != rightIndex){int tmpHeight;int tmpWidth = rightIndex - leftIndex;//短的一侧向中间移动if (height[leftIndex] < height[rightIndex]){tmpHeight = height[leftIndex];leftIndex++;}else{tmpHeight = height[rightIndex];rightIndex--;}int tmpResult = tmpWidth * tmpHeight;if (tmpResult > result){result = tmpResult;}}return result;}
  1. 整数转罗马数字

最简单的方式就是将罗马数字存储在数组中,然后依次查找填表即可,简单粗暴但是低效而且不美观:

class Solution {
public:string intToRoman(int num){string result;vector<string> tmpVec1 = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};vector<string> tmpVec2 = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};vector<string> tmpVec3 = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};vector<string> tmpVec4 = {"", "M", "MM", "MMM"};vector<vector<string>> store = {tmpVec1, tmpVec2, tmpVec3, tmpVec4};result.append(store[3][num / 1000 % 10]);result.append(store[2][num / 100 % 10]);result.append(store[1][num / 10 % 10]);result.append(store[0][num % 10]);return result;}
};

更好的做法是贪心算法:存储一个特殊数字的情况,挨个查找并减少数字

class Solution {
public:string intToRoman(int num){string result;int store[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};string strs[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};//贪心法for (int i = 0; i < 13; i++){while (num >= store[i]){result.append(strs[i]);num -= store[i];}}return result;}
};
  1. 罗马数字转整数
class Solution {
public:int romanToInt(string s) {unordered_map<char, int> mp;mp['I'] = 1;mp['V'] = 5;mp['X'] = 10;mp['L'] = 50;mp['C'] = 100;mp['D'] = 500;mp['M'] = 1000;int pos = 0, neg = 0;for (int i = 0;i < s.size()-1;++i){if (mp[s[i]] < mp[s[i+1]])neg -= mp[s[i]];elsepos += mp[s[i]];}pos += mp[s.back()];return pos + neg;           }
};
  1. 最长公共前缀
    编写一个函数来查找字符串数组中的最长公共前缀。
    如果不存在公共前缀,返回空字符串 “”。

最简单的办法就是循环迭代查找,该方法时间复杂度和空间复杂度均很低,而且容易想到。除此之外,还可以使用分治的方法,但是结果并没有更优秀

class Solution {
public:string longestCommonPrefix(vector<string>& strs) {int count = 0;int size = 0;char c;bool end = true;string ret;if (strs.size() == 0)return ret;vector<string>::iterator iter;iter = strs.begin();while (iter != strs.end()){if (size < (*iter).size())size = (*iter).size();iter++;}while (end){iter = strs.begin();c = (*iter)[count];while ((iter + 1) != strs.end()){iter++;if (c != (*iter)[count]){end = false;break;}}if (end){ret += c;count++;}	if (count >= size)return ret;}return ret;}
};

这篇关于leetcode解题思路分析(二)8-14题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138046

相关文章

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Redis中的有序集合zset从使用到原理分析

《Redis中的有序集合zset从使用到原理分析》Redis有序集合(zset)是字符串与分值的有序映射,通过跳跃表和哈希表结合实现高效有序性管理,适用于排行榜、延迟队列等场景,其时间复杂度低,内存占... 目录开篇:排行榜背后的秘密一、zset的基本使用1.1 常用命令1.2 Java客户端示例二、zse

Redis中的AOF原理及分析

《Redis中的AOF原理及分析》Redis的AOF通过记录所有写操作命令实现持久化,支持always/everysec/no三种同步策略,重写机制优化文件体积,与RDB结合可平衡数据安全与恢复效率... 目录开篇:从日记本到AOF一、AOF的基本执行流程1. 命令执行与记录2. AOF重写机制二、AOF的

MyBatis Plus大数据量查询慢原因分析及解决

《MyBatisPlus大数据量查询慢原因分析及解决》大数据量查询慢常因全表扫描、分页不当、索引缺失、内存占用高及ORM开销,优化措施包括分页查询、流式读取、SQL优化、批处理、多数据源、结果集二次... 目录大数据量查询慢的常见原因优化方案高级方案配置调优监控与诊断总结大数据量查询慢的常见原因MyBAT

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

Java中最全最基础的IO流概述和简介案例分析

《Java中最全最基础的IO流概述和简介案例分析》JavaIO流用于程序与外部设备的数据交互,分为字节流(InputStream/OutputStream)和字符流(Reader/Writer),处理... 目录IO流简介IO是什么应用场景IO流的分类流的超类类型字节文件流应用简介核心API文件输出流应用文

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

MySQL中读写分离方案对比分析与选型建议

《MySQL中读写分离方案对比分析与选型建议》MySQL读写分离是提升数据库可用性和性能的常见手段,本文将围绕现实生产环境中常见的几种读写分离模式进行系统对比,希望对大家有所帮助... 目录一、问题背景介绍二、多种解决方案对比2.1 原生mysql主从复制2.2 Proxy层中间件:ProxySQL2.3