LeetCode刷题
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
链接:https://leetcode-cn.com/problems/two-sum
解法一:暴力
class Solution {
public int[] twoSum(int[] nums, int target) {
int n = nums.length;
for (int i = 0; i < n; ++i) {
//以i+1为起始搜索地址,避免返回结果里有重复元素
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return new int[]{
i, j};
}
}
}
return null;
}
}
时间复杂度:两层 for 循环,O(n²)
空间复杂度:O(1)
解法二:哈希表
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> table = new HashMap<>();
int n = nums.length;
for(int i = 0; i < n; i++) {
//将所有元素与其对应的位置存入哈希表
table.put(nums[i],i);
}
for (int i = 0; i < n; i++) {
int toFind = target-nums[i];
//如果哈希表中有我们需要寻找的数
if(table.containsKey(toFind)) {
//并且这个数并不是nums[i]本身
int pos = table.get(toFind);
if(pos != i) return new int[] {
i,pos};
}
}
return null;
}
}
时间复杂度:O(n),但是在leetcode上提交时,时间效率并不如暴力解法好
空间复杂度:O(n)
解法三:哈希表优化
解法二用到的是两个for循环,可以只用一个for循环解决这道题。
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> table = new HashMap<>();
int n = nums.length;
for(int i = 0; i < n; i++) {
if(table.containsKey(nums[i])) {
//如果包含当前指针所在元素,那么说明已经找到,返回结果
return new int[]{
table.get(nums[i]),i};
}
//注意这里不是存放(nums[i],i),而是(target-nums[i],i)
//这样等循环遍历到了数组中某个等于target-nums[i]的数时
//可以通过哈希表搜索直接获取到i
table.put(target-nums[i],i);
}
return null;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
2. 两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例 1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
链接:https://leetcode-cn.com/problems/add-two-numbers
思路:
两条链表同一位置元素相加,如有进位则将jinWei标记为1。
如此遍历直到两条链表尾且jinWei为0。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int jinWei = 0;
ListNode head = null, p = null;
while(l1 != null || l2 != null || jinWei != 0) {
int num = 0;
if(l1 != null) {
num += l1.val;
l1 = l1.next;
}
if(l2 != null) {
num += l2.val;
l2 = l2.next;
}
num += jinWei;
if(head == null) {
head = new ListNode(num%10);
p = head;
} else{
p.next = new ListNode(num%10);
p = p.next;
}
if(num >= 10) {
jinWei = 1;
}else {
jinWei = 0;
}
}
return head;
}
}
3. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
示例 4:
输入: s = ""输出: 0
链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
解法一:哈希表
很容易想到用哈希表记录字符和其对应的位置。
class Solution {
public int lengthOfLongestSubstring(String s) {
int ans = 0; int start = 0; //从哪里开始截断重新开始计数 if(s.length() == 0) return ans; HashMap<Character,Integer> hm = new HashMap<>(); for(int i = 0; i < s.length(); i++) { char now = s.charAt(i); if(hm.containsKey(now)) { start = Math.max(start,hm.get(now)+1); } hm.put(now,i); ans = Math.max(ans,i-start+1); } return ans; }}
时间复杂度:O(n)
空间复杂度:使用了一个哈希表,判断子串中有没有重复的字符。由于 hm 中没有重复的字符,所以最长就是整个字符集,假设字符集的大小为 m ,那么 hm最长就是 m 。另一方面,如果字符串的长度小于 m ,是 n 。那么 hm 最长也就是 n 了。综上,空间复杂度为 O(min(m,n))。
解法二:数组
哈希表的搜索方式本质上也是遍历搜寻,可以将哈希表优化为一个数组。字符的 ASCII 码值作为数组的下标,数组存储该字符所在字符串的位置。
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) return 0;
int ans = 0;
int start = 0;
int[] map = new int[128];
char[] chars = s.toCharArray();//这里转换成char数组有利于提高速度
for(int i = 0; i < chars.length; i++) {
int cur = chars[i];
if(map[cur] != 0) {
start = Math.max(map[cur],start);
}
map[cur] = i+1;
ans = Math.max(ans, i-start+1);
}
return ans;
}
}
时间复杂度:O(n)。
空间复杂度:O(1)。开辟的数组空间大小是不变的。
4. 寻找两个正序数组的中位数
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
解法一:
因为是寻找中位数,所以可知实际上就是寻找第K小的数。
可以分别给两个数组两个指针,移动指向比较小的那个数的指针
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
if((m+n)%2 == 0) return ((double)getK(nums1,nums2,(m+n+1)/2) + (double)getK(nums1, nums2, (m+n+2)/2))/2;
return getK(nums1,nums2,(m+n+1)/2);
}
private int getK(int[] nums1, int[] nums2, int k) {
int p1 = 0, p2 = 0;
int m = nums1.length, n = nums2.length;
while(p1 < m || p2 < n) {
if(p1+p2+1 == k) {
if(p1 == m) {
//如果第一个指针已经越界
return nums2[p2];//直接返回数组二里的数
}else if(p2 == n) {
//如果第二个指针越界
return nums1[p1];//返回数组一中的数
}else {
//如果两个指针都没越界,那么返回较小的那个
return Math.min(nums1[p1],nums2[p2]);
}
}
if(p1 == m) {
//如果第一个数组已经遍历完
p2++;//移动数组二的指针
}else if(p2 == n){
//如果第二个数组已经遍历完
p1++;//移动数组一的指针
}else {
//如果两个数组都还没遍历完
//比较大小
if(nums1[p1] < nums2[p2]) {
p1++;
}else {
p2++;
}
}
}
return -1;
}
}
时间复杂度:O(m+n),达不到题目中要求的O(log(m+n))。
空间复杂度: O(1)。
解法二:二分法
题目要求的时间复杂度是O(log(m+n)),很自然会联想到二分查找法。其实就是在解法一的基础上运用了二分查找法来筛查到第K小的数。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length; if((m+n)%2 == 1) return getK(nums1,0,nums2,0,(m+n+1)/2); return ((double)getK(nums1,0,nums2,0,(m+n+1)/2) + (double)getK(nums1,0,nums2,0,(m+n+2)/2))/2; } private int getK(int[] nums1, int start1, int[] nums2, int start2, int k) {
if(start1 == nums1.length) return nums2[start2 + k - 1]; if(start2 == nums2.length) return nums1[start1 + k - 1]; if(k == 1) return nums1[start1] <= nums2[start2] ? nums1[start1] : nums2[start2]; //防止数组越界 int len1 = Math.min(start1 + k/2 - 1, nums1.length - 1); int len2 = Math.min(start2 + k/2 - 1, nums2.length - 1); if(nums1[len1] <= nums2[len2]) { //舍弃掉nums1[len1]及之前的所有数,从len1+1位置开始搜寻 //剩下的所有数中要找寻第k-(len1-start1+1)小的数 return getK(nums1, len1 + 1, nums2, start2, k-(len1-start1+1)); } return getK(nums1, start1, nums2, len2 + 1, k-(len2-start2+1)); }}
5. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = "babad"输出:"bab"解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd"输出:"bb"
示例 3:
输入:s = "a"输出:"a"
示例 4:
输入:s = "ac"输出:"a"
链接:https://leetcode-cn.com/problems/longest-palindromic-substring
解法一:暴力解
暴力求解,列举所有的子串,判断是否为回文串。
class Solution {
public String longestPalindrome(String s) {
if(s.length() == 1) return s; char[] array = s.toCharArray(); int longest = 1;//因为每单个字符一定是回文串,所以可以确定的是最长的回文串一定大于等于1 int left = 0, right = 0; for(int i = 0; i < array.length - longest; i++) { //一点简单的剪枝操作 for(int j = i+longest; j < array.length; j++) { if(isPalindrome(array, i, j)) { longest = j - i + 1; left = i; right = j; } } } return s.substring(left,right+1); } private boolean isPalindrome(char[] array, int left, int right) { while(left < right) { if(array[left] == array[right]) { left++; right--; }else { return false; } } return true; }}
时间复杂度:两层 for 循环 O(n²),for 循环里边判断是否为回文,O(n),所以时间复杂度为 O(n³)。
空间复杂度:O(n),如果不将字符串转化成char数组则只需要O(1)。
解法二:暴力优化(动态规划)
用一个二维布尔数组isP[i] [j] 表示从位置i到j是否为回文串,如果i位置和j位置的字符相同,且isP[i+1] [j-1]为真,那么可以得出isP[i] [j]为真。
class Solution{
public String longestPalindrome(String s) {
if(s.length() == 1) return s; int length = s.length(); boolean[][] isP = new boolean[length][length]; char[] chars = s.toCharArray(); int left = 0, right = 0; for(int i = 0; i < length; i++) {
isP[i][i] = true; } for(int len = 2; len <= length; len++) {
for(int start = 0; start <= length - len; start++){
int end = start + len - 1; isP[start][end] = (chars[start] == chars[end]) && (len == 2 || isP[start+1][end-1]); if(isP[start][end]) {
left = start; right = end; } } } return s.substring(left,right+1); }}
时间复杂度:两层循环,O(n²)。
空间复杂度:用二维数组保存每个子串的情况,O(n²)。
这里的空间复杂度还可以优化,可以尝试用一维数组来表示isP[j]表示。由于isP[i] [j]是从isP[i+1] [j-1]得到的,所以知道以i为起始的isP必须要先得到i+1的isP。遍历顺序应当是倒序。
class Solution{
public String longestPalindrome(String s) {
if(s.length() == 1) return s; int length = s.length(); boolean[] isP = new boolean[length]; char[] chars = s.toCharArray(); int left = 0, right = 0, longest = 1; for(int i = length - 1; i >= 0; i--) {
for(int j = length - 1; j >= i; j--){
isP[j] = (chars[i] == chars[j]) && (j - i <= 2 || isP[j-1]); if(isP[j] && j - i + 1 > longest) {
left = i; right = j; longest = j - i + 1; } } } return s.substring(left,right+1); }}
时间复杂度:两层循环,O(n²)。
空间复杂度:O(n)。
解法三:中心扩展
以中间为搜寻起点,如果是回文子串则向两边散开。
class Solution {
public String longestPalindrome(String s) {
if(s.length() == 1) return s; char[] array = s.toCharArray(); int[] memo = {
0,0,0};//保存最长回文长度,左边界索引,右边界索引 for(int i = 1; i < array.length - memo[0]/2; i++) { countPalindrome(array, i, i, memo); countPalindrome(array, i-1, i, memo); } return s.substring(memo[1],memo[2]+1); } private void countPalindrome(char[] a, int left, int right, int[] memo) { while(left >= 0 && right < a.length && a[left] == a[right]) { left--; right++; } if(right - left - 1 > memo[0]) { memo[0] = right - left - 1; memo[1] = left + 1; memo[2] = right - 1; } }}
时间复杂度:一层 for 循环 O(n),for 循环里边判断是否为回文,O(n),所以时间复杂度为 O(n²)。
空间复杂度:O(n),如果不将字符串转化成char数组则只需要O(1)。
解法四:动态规划
如果一个字符串是回文串,那么其正序和倒序读起来都是一样的,以字符串“caba“为例,将其倒过来是"abac",最长公共子串是"aba",所以"aba"就是我们要寻找的最长回文子串。
把两个字符串分别以行和列组成一个二维矩阵,如果字符串1的i位置和字符串2的j位置相等,那么就用dp[i] [j]=1 +dp[i-1] [j-1]更新。
class Solution {
public String longestPalindrome(String s) {
if(s.length() == 1) return s; char[] array = s.toCharArray(); int longest = 1;//因为每单个字符一定是回文串,所以可以确定的是最长的回文串一定大于等于1 int left = 0, right = 0; int[][] dp = new int[array.length][array.length]; //以逆序数组为行,正序数组为列 for(int i = 0; i < array.length; i++) { for(int j = 0; j < array.length; j++) { if(array[j] == array[array.length - 1 - i]) { dp[i][j] = ((i > 0 && j > 0) ? dp[i-1][j-1] : 0) + 1; if(dp[i][j] > longest) { if(j - dp[i][j] + 1 == array.length - 1 - i) { //确认一下下标无误,即正序开始时的下标等于array.length - 1减去逆序位置i //如果不加这一步确认那么遇到例如"aacabdkacaa"时,会出现dp[3][3]最大,left=7,right = 3 longest = dp[i][j]; right = j; left = array.length - 1 - i; } } } } } return s.substring(left,right+1); }}
时间复杂度:两层循环,O(n²)。但是不如中心扩展效率好,因为中心扩展法有剪枝操作,而利用动态规划无法这么做。
空间复杂度:一个二维数组,O(n²)。
可以只用一维数组来优化空间复杂度。
class Solution {
public String longestPalindrome(String s) {
int length = s.length(); if(length == 1) return s; char[] array = s.toCharArray(); int longest = 1;//因为每单个字符一定是回文串,所以可以确定的是最长的回文串一定大于等于1 int left = 0, right = 0; int[] dp = new int[length]; //以逆序数组为行,正序数组为列 for(int i = 0; i < length; i++) { for(int j = length - 1; j >= 0; j--) { if(array[j] == array[array.length - 1 - i]) { dp[j] = ((j > 0) ? dp[j-1] : 0) + 1; if(dp[j] > longest) { if(j - dp[j] + 1 == array.length - 1 - i) { //确认一下下标无误,即正序开始时的下标等于array.length - 1减去逆序位置 longest = dp[j]; right = j; left = array.length - 1 - i; } } }else { //之前二维数组,每次用的是不同的列,所以不用置 0 。 dp[j] = 0; } } } return s.substring(left,right+1); }}
6. Z 字形变换
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"
示例 2:
输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入:s = "A", numRows = 1
输出:"A"
链接:https://leetcode-cn.com/problems/zigzag-conversion
解法一:找规律,求通项
当输入numRows = 5时:
可以看到第0行间隔是8((numRows - 1)*2)
第一行间隔是6((numRows - 1 - 1)*2)和2(1 * 2)
第二行间隔是4((numRows - 1 - 2)*2)和4(2 * 2)
第三行间隔是2((numRows - 1 - 3)*2)和6(3 * 2)
第四行间隔是8(4 * 2)
class Solution {
public String convert(String s, int numRows) {
if(numRows == 1 || s.length() <= numRows) return s; char[] chars = s.toCharArray(); int row = 0; StringBuilder sb = new StringBuilder(); while(row < numRows) {
int pos = row; //当step1和step2为0时要特殊处理 int step1 = (numRows - row - 1) * 2 == 0 ? row * 2 : (numRows - row - 1) * 2; int step2 = row * 2 == 0 ? step1 : row * 2; boolean isS1 = true; while(pos < chars.length) { sb.append(chars[pos]); if(isS1){ pos += step1; isS1 = false; }else { pos += step2; isS1 = true; } } row++; } return sb.toString(); }}
解法二:Z字存储
按照写 Z 的过程,遍历每个字符,然后将字符存到对应的行中。用upNotDown表示当前进行方向,如果为false代表要往下写,所以row要加一;如果为true,row要减一。
class Solution {
public String convert(String s, int numRows) {
if(numRows == 1 || s.length() <= numRows) return s; char[] chars = s.toCharArray(); List<StringBuilder> rows = new ArrayList<StringBuilder>(); boolean upNotDown = false; int row = 0; for(int i = 0; i < numRows; i++) {
rows.add(new StringBuilder()); } for(char c : chars) {
rows.get(row).append(c); if(upNotDown) {
row--; if(row == 0) upNotDown = false; }else {
row++; if(row == numRows - 1) upNotDown = true; } } StringBuilder sb = new StringBuilder(); for (StringBuilder r : rows) sb.append(r); return sb.toString(); }}
7. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
链接:https://leetcode-cn.com/problems/reverse-integer
本题唯一的难点就在于溢出,例如若输入为1534236469,倒置过来不应该是 9646324351 吗。其实题目里讲了,int 的范围是
[ − 2 31 , 2 31 − 1 ] [-2^{31} ,2^{31}-1] [−231,231−1]
也就是 [ -2147483648 , 2147483647 ] 。明显 9646324351 超出了范围,造成了溢出。所以我们需要在输出前,判断是否溢出。可以直接将保存数据类型int改为long,返回数值时直接利用强转int即可。
class Solution {
public int reverse(int x) {
//个位数单独处理,直接返回即可
if((x >= 0 && x <= 9) || (x < 0 && x > -10)) return x;
boolean negative = false;
if(x < 0) {
negative = true;
x = Math.abs(x);
}
long res = 0;
while(x > 0) {
res = res * 10 + x % 10;
if (res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) return 0;
x /= 10;
}
if(negative) res = - res;
return (int)res;
}
}
8. 字符串转换整数 (atoi)
请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
函数 myAtoi(string s) 的算法如下:
读入字符串并丢弃无用的前导空格
检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
如果整数数超过 32 位有符号整数范围 [−231, 231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
返回整数作为最终结果。
注意:
本题中的空白字符只包括空格字符 ’ ’ 。
除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
示例 1:
输入:s = "42"
输出:42
解释:加粗的字符串为已经读入的字符,插入符号是当前读取的字符。
第 1 步:"42"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"42"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"42"(读入 "42")
^
解析得到整数 42 。
由于 "42" 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:
输入:s = " -42"
输出:-42
解释:
第 1 步:" -42"(读入前导空格,但忽视掉)
^
第 2 步:" -42"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:" -42"(读入 "42")
^
解析得到整数 -42 。
由于 "-42" 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:
输入:s = "4193 with words"
输出:4193
解释:
第 1 步:"4193 with words"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"4193 with words"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"4193 with words"(读入 "4193";由于下一个字符不是一个数字,所以读入停止)
^
解析得到整数 4193 。
由于 "4193" 在范围 [-231, 231 - 1] 内,最终结果为 4193 。
示例 4:
输入:s = "words and 987"
输出:0
解释:
第 1 步:"words and 987"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"words and 987"(当前没有读入字符,因为这里不存在 '-' 或者 '+')
^
第 3 步:"words and 987"(由于当前字符 'w' 不是一个数字,所以读入停止)
^
解析得到整数 0 ,因为没有读入任何数字。
由于 0 在范围 [-231, 231 - 1] 内,最终结果为 0 。
示例 5:
输入:s = "-91283472332"
输出:-2147483648
解释:
第 1 步:"-91283472332"(当前没有读入字符,因为没有前导空格)
^
第 2 步:"-91283472332"(读入 '-' 字符,所以结果应该是负数)
^
第 3 步:"-91283472332"(读入 "91283472332")
^
解析得到整数 -91283472332 。
由于 -91283472332 小于范围 [-231, 231 - 1] 的下界,最终结果被截断为 -231 = -2147483648 。
链接:https://leetcode-cn.com/problems/string-to-integer-atoi
本题要尤其注意测试样例 “ +4” 、“±12”、“00000-42a1234”。这代表除了‘-’,’+‘也要考虑,且一旦前面出现了有效的字符后面再出现除数字以外的任何字符都是不作数的。
class Solution {
public int myAtoi(String s) {
if(s.length() == 0) return 0; char[] chars = s.toCharArray(); long res = 0; //结果用long防止溢出 boolean negative = false; //表示是否为负数 boolean hasMet = false; //表示之前已经遇到了有效字符 for(char c : chars) { if(!hasMet && c == '-' && res == 0) { negative = true; hasMet = true; }else if(!hasMet && c == '+' && res == 0){ negative = false; hasMet = true; }else if(!hasMet && c == ' ' && res == 0){ continue; }else{ int cur = c - 48; if(cur >= 0 && cur <= 9){ hasMet = true; res = res * 10 + cur; }else { break; } if(negative && res > 2147483648L) return -2147483648; if(!negative && res >= 2147483648L) return 2147483647; } } if(negative) res = -res; return (int)res; }}
9. 回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
示例 1:
输入:x = 121
输出:true
示例 2:
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。
示例 4:
输入:x = -101
输出:false
链接:https://leetcode-cn.com/problems/palindrome-number、
解法一:整数反转
题目要求了不能用将int转成string的方法来写这题,那么可以用第七题整数反转的方法。
class Solution {
public boolean isPalindrome(int x) {
if(x >= 0 && x < 10) return true; //只有个位数一定是回文
if(x < 0 || x%10 == 0) return false; //负数或者是末尾为0的情况都排除
int reverse = 0, tmp = x;
while(tmp > 0) {
reverse = reverse * 10 + tmp % 10;
tmp /= 10;
}
return (x == reverse);
}
}
时间复杂度:和求转置一样,x 有多少位,就循环多少次,所以是 O(log(x)) 。
空间复杂度:O(1)。
解法二:整数反转一半
其实,我们只需要将右半部分倒置然后和左半部比较就可以了。
class Solution {
public boolean isPalindrome(int x) {
if(x >= 0 && x < 10) return true;