目录
- 1. 两数之和
 - 2. 两数相加
 - 3.无重复字符的最长子串
 - 4.寻找两个正序数组的中位数
 - 5.最长回文子串
 - 6.N 形变换
 - 7.整数反转
 - 8.字符串转整数(atoi)
 - 9.回文数
 - 10. 正则表达式匹配
 - 11. 盛最多水的容器
 - 12. 整数转罗马数字
 - 13. 罗马数字转整数
 - 14. 最长公共前缀
 - 15.三数之和
 - 16.最接近的三数之和
 - 17.电话号码的字母组合
 - 总结
 - 声明
 
1. 两数之和
给定一个整数数组
nums和一个整数目标值target,请你在该数组中找出和为目标值target的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
数组中存在两个数 x x x 和 y y y ,使得 x + y = t a r g e t x+y=target x+y=target 。
可以直接枚举数组中的所有可能的两数组合可能,找到答案。
for(int i = 0; i < nums.size(); ++i){
	for(int j = i + 1; j < nums.size(); ++j){
		if (nums[i] + nums[j] == target) break;
	}
}
 
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
双指针
题目核心为查找, 对于查找,我们一般会先对数组排序。这样我们就可使用二分查找,也能进行更多有规律的操作。
(1)将数组nums[i]升序排序
(2)取指针l,r 分别指向nums的首、尾,即l = 0, r = nums.size() - 1。
(3)如果nums[l] + nums[r] == target ,则返回结果。如果nums[l] + nums[r] > target ,说明则让 r--。否则, l++ 。
(4)直至找到答案或l >= r。

如果
nums[l] + nums[r] > target, 说明两数和大于目标值。所以需要将两数和减少,这样才可能找到答案。由于我们数组已经升序排好了,所以让右边的r左移一位,使得nums[r] 变小,变为nums[r-1]。如果两数和小于目标值,则需要将nums[l]变成nums[l+1],实现两数和增大。然后继续比较,逐渐逼近答案。
sort(vec.begin(), vec.end());
while(l < r){
    int temp = vec[l] + vec[r];
    if(temp == target) break;
    else if(temp > target) r--;
    else l++;
}
 
时间复杂度: O ( n log  2 n ) O(n\log_2n) O(nlog2n)
空间复杂度: O ( n ) O(n) O(n)
哈希表
对于 
     
      
       
       
         n 
        
       
         u 
        
       
         m 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        num[i] 
       
      
    num[i],需要找到个nums[j], 使得 
     
      
       
       
         n 
        
       
         u 
        
       
         m 
        
       
         s 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         + 
        
       
         n 
        
       
         u 
        
       
         m 
        
       
         s 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         = 
        
       
         t 
        
       
         a 
        
       
         r 
        
       
         g 
        
       
         e 
        
       
         t 
        
       
      
        nums[j] + nums[i] = target 
       
      
    nums[j]+nums[i]=target ,即数组中取一个数 nums[i] 需要查找 target - nums[i] 。
借助哈希表,实现查找复杂度为 O ( 1 ) O(1) O(1)
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
    auto it = hashtable.find(target - nums[i]);
    if (it != hashtable.end()) {
        return {it->second, i};
    }
    hashtable[nums[i]] = i;
}
 
2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
链表结点存放数字,取出相加即可。需要注意进位以及当两链表长度不同时,带来的其中一链表可能提前遍历到尾部,使指针为空。
解决也很简单
(1)创建一个变量carry,用来存放进位值。
(2)当一链表遍历结束时,另一链表未结束,此时循环还在继续。将遍历结束的链表的结点值设为0即可。
int x = l1 ? l1->val : 0;  // l1 和 l2 是两个真在遍历的链表
int y = l2 ? l2->val : 0;
 
还有就是可能最高位运算也会产生进位,此时需要新建一个结点存值
3.无重复字符的最长子串
给定一个字符串
s,请你找出其中不含有重复字符的 最长子串 的长度。
思路也不难。区间内不含重复字符。
首先,需要两个指针l, r 来指代正在遍历的区间。然后让r++,来拓展区间。如果 s[r+1] 在区间内已存在,说明一找出一个不重复子串,记录长度。接着需要将l++ 来减小区间,含重复的字符的区间缩小到不含重复字符。

判断区间内是否含重复字符,借助哈希集合可以快速判断。
4.寻找两个正序数组的中位数
给定两个大小分别为
m和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为O(log (m+n))。
简单点,直接合并两数组,然后在找中位数。
其他方法,不会。
5.最长回文子串
给你一个字符串
s,找到s中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
选定区间左边界 i ,依次缩小右边界 j,知道 [i, j] 是回文串。这样找到 s[i] 为开始的最长回文子串。
依次找到所有位置开始的最长子串,选最长,即为答案。
优化
可以进行简单的优化。比如已求的最优长子串为长度为 ans,输入串 s 的长度为 n。
(1)如果 n - i < ans  ,那循环结束。说明以 i 开始的最长的子串都长度都小于ans,那么以i开始的最长回文串也一定会小于ans,所以没必要在求最优子串。
(2)同样,如果 [i, j] 区间的长度小于 ans,也没必要在继续减小 j 求以 i 开始的最优回文串了 。
6.N 形变换
将一个给定字符串
s根据给定的行数numRows,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为
"PAYPALISHIRING"行数为3时,排列如下:P A H N A P L S I I G Y I R之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:
"PAHNAPLSIIGYIR"。
直接遍历。大循环套俩小循环。先竖着遍历存储(PAY),然后遍历存储(P)。接着继续竖直存储,斜着遍历。
设置好存储结构,加点简单判断。搞清楚结束条件。
7.整数反转
给你一个 32 位的有符号整数
x,返回将x中的数字部分反转后的结果。如果反转后整数超过 32 位的有符号整数的范围
[−231, 231 − 1],就返回 0。假设环境不允许存储 64 位整数(有符号或无符号)。
x % 10 : 取x的最低位数值。
x /= 10 : 去除x的最低位,相当于10进制的x右移一位。
遍历过程中,别溢出就行。
8.字符串转整数(atoi)
请你来实现一个
myAtoi(string s)函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的atoi函数)。
多写几个判断就行。注意,要提前判断整数是否溢出,溢出返回0。
判断方式: res > (INT_MAX - digit) / 10
9.回文数
给你一个整数
x,如果x是一个回文整数,返回true;否则,返回false。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
- 例如,
 121是回文,而123不是。
转换成字符串,判断是否是回文串就行。
10. 正则表达式匹配
给你一个字符串
s和一个字符规律p,请你来实现一个支持'.'和'*'的正则表达式匹配。
'.'匹配任意单个字符'*'匹配零个或多个前面的那一个元素所谓匹配,是要涵盖 整个 字符串
s的,而不是部分字符串。
没写出来。
看了题解,理清思路,不停判断。懒得看。
11. 盛最多水的容器
给定一个长度为
n的整数数组height。有n条垂线,第i条线的两个端点是(i, 0)和(i, height[i])。找出其中的两条线,使得它们与
x轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
**说明:**你不能倾斜容器。
感觉有点像第1题的那个寻找两数之和的左右指针的方式。
选定区间[l, r], 那么盛水量为 ans = max( ans, min(height[l], height[r]) * (r - l) ) 。
此后,区间长度(r-l)不停缩小,如果想让ans变大,只可能将 min(height[l], height[r]) 变大,所以只需要将height[i] 和 height[j]小的一边移动,大的另一边不动。这样min(height[l], height[r]) * (r - l) 的 min(height[l], height[r]) 变大, (r - l) 变小,二者的乘积才有可能增大,即盛水量增大。
int i = 0, j = height.size() - 1, res = 0;
while(i < j) {
    res = height[i] < height[j] ? 
        max(res, (j - i) * height[i++]): 
    max(res, (j - i) * height[j--]); 
}
 
12. 整数转罗马数字
罗马数字包含以下七种字符:
I,V,X,L,C,D和M。字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000例如, 罗马数字 2 写做
II,即为两个并列的 1。12 写做XII,即为X+II。 27 写做XXVII, 即为XX+V+II。通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做
IIII,而是IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为IX。这个特殊的规则只适用于以下六种情况:
I可以放在V(5) 和X(10) 的左边,来表示 4 和 9。X可以放在L(50) 和C(100) 的左边,来表示 40 和 90。C可以放在D(500) 和M(1000) 的左边,来表示 400 和 900。给你一个整数,将其转为罗马数字。
搞清楚规则,然后写个循环模拟判断选择即可。
如果大于M,先减M。否则如果大于IM,减IM。否则如果小于D,减D。。。不停判断下去就行。
13. 罗马数字转整数
罗马数字包含以下七种字符:
I,V,X,L,C,D和M。字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000例如, 罗马数字
2写做II,即为两个并列的 1 。12写做XII,即为X+II。27写做XXVII, 即为XX+V+II。通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做
IIII,而是IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为IX。这个特殊的规则只适用于以下六种情况:
I可以放在V(5) 和X(10) 的左边,来表示 4 和 9。X可以放在L(50) 和C(100) 的左边,来表示 40 和 90。C可以放在D(500) 和M(1000) 的左边,来表示 400 和 900。给定一个罗马数字,将其转换成整数。
找出规律,再写。
对于特殊的IV, IX,IC 都满足类似以下的规律:
IV: I V = − I + V = − 1 + 5 = 4 = I V IV=-I+V = -1 + 5 = 4 = IV IV=−I+V=−1+5=4=IV
所以如果ans = s[i] < s[i+1] ? ans - getValue(s[i]) : ans + getValue(s[i])。 其中, i < s.length()-1,防止i+1访问越界。
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串
""。
纵向比对,即可。
15.三数之和
给你一个整数数组
nums,判断是否存在三元组[nums[i], nums[j], nums[k]]满足i != j、i != k且j != k,同时还满足nums[i] + nums[j] + nums[k] == 0。请你返回所有和为
0且不重复的三元组。**注意:**答案中不可以包含重复的三元组。
在第一题的两数之和基础上略作改变皆可。nums[i] + nums[j] = -nums[k]。
16.最接近的三数之和
给你一个长度为
n的整数数组nums和 一个目标值target。请你从nums中选出三个整数,使它们的和与target最接近。返回这三个数的和。
假定每组输入只存在恰好一个解。
类比上一题的三数之和。
17.电话号码的字母组合
给定一个仅包含数字
2-9的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
建立一个从数字到字母的映射表,然后进行简单回溯即可。
总结
这17期道题目,还是比较基础的。主要考察的还是一些简单的思路分析,使用双指针,滑动窗口和特殊的数据结构,比如哈希表和哈希集合。没有特别难的算法和数据结构。但收获还是很多的。
声明
题目全部来自LeetCode官网,部分题解参考了官方题解。




















