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

相关文章

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

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

MySQL中EXISTS与IN用法使用与对比分析

《MySQL中EXISTS与IN用法使用与对比分析》在MySQL中,EXISTS和IN都用于子查询中根据另一个查询的结果来过滤主查询的记录,本文将基于工作原理、效率和应用场景进行全面对比... 目录一、基本用法详解1. IN 运算符2. EXISTS 运算符二、EXISTS 与 IN 的选择策略三、性能对比

MySQL 内存使用率常用分析语句

《MySQL内存使用率常用分析语句》用户整理了MySQL内存占用过高的分析方法,涵盖操作系统层确认及数据库层bufferpool、内存模块差值、线程状态、performance_schema性能数据... 目录一、 OS层二、 DB层1. 全局情况2. 内存占js用详情最近连续遇到mysql内存占用过高导致

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

Olingo分析和实践之EDM 辅助序列化器详解(最佳实践)

《Olingo分析和实践之EDM辅助序列化器详解(最佳实践)》EDM辅助序列化器是ApacheOlingoOData框架中无需完整EDM模型的智能序列化工具,通过运行时类型推断实现灵活数据转换,适用... 目录概念与定义什么是 EDM 辅助序列化器?核心概念设计目标核心特点1. EDM 信息可选2. 智能类

Olingo分析和实践之OData框架核心组件初始化(关键步骤)

《Olingo分析和实践之OData框架核心组件初始化(关键步骤)》ODataSpringBootService通过初始化OData实例和服务元数据,构建框架核心能力与数据模型结构,实现序列化、URI... 目录概述第一步:OData实例创建1.1 OData.newInstance() 详细分析1.1.1