您的位置:首页 > 其它

LeetCode-Easy1.1:两数之和、整数反转、回文整数

2020-02-02 08:36 537 查看

开新坑

各路师兄建议早点开刷,积累才是关键,虽然论文方向还没着落,但是以后该做的准备得做好。

Easy篇

对于一个自学完数据结构和算法的新手,Easy篇的难度足以让人捶胸顿足。我把难度的定义不在于你做不出来,而是吸收别人的精华的难度。虽然是一个简单的小功能,但照师兄说的,如何优化到极致才是关键的。

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例: 给定 nums = [2, 7, 11, 15],
target = 9 因为 nums[0] + nums[1]= 2 + 7 = 9 所以返回 [0, 1]

大体瞅一眼,其实是两个for循环就能解决的事情,O(n2)的时间复杂度让这个题的没办法从算法角度的去优化,而HashTable这种数据结构成为解决这个问题的关键。

解法:两次遍历

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;
for(int i  = 0; i<nums.size();++i)
a.insert(map<int,int>::value_type(nums[i],i));
for(int i = 0;i<nums.size();++i){
if(a.count(target-nums[i])>0&&a[target-nums[i]]!=i)
return {i,a[target-nums[i]]};
}
return {0,0};
}
};

哈希表的key用来存储nums的各个值,value用来存储nums的下标,先将映射关系保存到哈希表a中。这要对nums遍历一次。
然后对nums的每个元素进行遍历,直接搜索哈希表中有没有target-nums[i]这个键值,这里对nums遍历一次。
所以,这个地方成为了代码降低时间复杂度的关键,传统的两次for循环的第二次for循环就是为了在列表中逐个比较才能知道是否有target-nums[i],而哈希表是直接通过target-nums[i]计算存储位置(count方法)。一个是逐个找,另一个是直接算,二者的时间复杂度不言而喻,

改进:一次遍历

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;
for(int i = 0;i < nums.size(); ++i){
if(a.count(target-nums[i])>0&&a[target-nums[i]] != i)
return{a[target-nums[i]],i};
a.insert(map<int,int>::value_type(nums[i],i));
}
return{0,0};
}
};

相对于两次遍历,一次遍历是在计算存储位置之后,如果哈希表中没有满足条件的key值,就顺便插入新的键值对,如果满足条件就直接返回。二者实质相同,后者更加优美。

整数反转

给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0

示例 1:

输入: 123
输出: 321
示例 2:

输入: -123
输出: -321
示例 3:

输入: 120
输出: 21

这个当年计算机二级考了无数遍,但是均没有考虑溢出的情况。但是这个题难度纯粹是考察对内置类型的运用,关键是对于溢出的解决。

解法:除10保留余数和商

最传统的解法就是这个,但是考虑不周的同学可能依然会用32位的内置类型(int)存储整数反转的结果sum。
虽然这种方法可以通过绝大部分的测试用例,但仍然有一小部分测试用例没办法通过。
例如231-1=2147483647,-231=-2147483648,如果选择231-1=2147483647作为需要翻转的数字,那么翻转到最后一位的时候就会溢出报错。
所以最简单的解决方法就是在做翻转计算的时候,sum的类型采用long型,返回之前判断转换成int是否溢出即可。

#define Integer_MAX_VALUE 2147483647
#define Integer_MIN_VALUE -2147483647
class Solution {
public:
int reverse(int x) {
long sum = 0;
while(x!=0){
sum = sum*10+x%10;
x = x/10;
}
if(sum<Integer_MIN_VALUE||sum>Integer_MAX_VALUE)
return 0;
return sum;
}
};

回文整数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:

输入: 121
输出: true
示例 2:

输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:

输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。

此题将各位数字转换成字符串,然后用字符串判断回文的算法去解决没有任何问题,但就时间复杂度而言,以上做法将各位数字遍历两次。
其实如果没有上一题的铺垫,那么这一题很容易就陷入思维定势。实际上,翻转以后依然是数字,只需考虑翻转以后是否相等即可。

解决:先翻转,后比较,

显然,题干上就是误导我们用判断字符串回文的方法去解题(不然-121反转成121-考虑成整数翻转求解也太不符合常理了…)
因此,负数翻转一定不符合题干中的回文要求,剩下的就是对正整数的翻转比较。

class Solution {
public:
bool isPalindrome(int x) {
if(x<0)
return false;
long b = 0;
int x1 = x;
while(x){
b = b*10+x%10;
x = x/10;
}
if(x1 != b)
return false;
return true;
}
};

当然,翻转的时候要注意第二题中在计算sum时会溢出的情况,事先用long型避免掉这个问题。
其次,这个题只是值比较,不需要32位值返回,因此也不需要做溢出比较。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
标准的搬运工 发布了7 篇原创文章 · 获赞 5 · 访问量 1522 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: