Java解leetcode,助力面试之简单10道题(十一)
第66题 加一
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
示例 1:
输入 | 输出 |
---|---|
digits = [1,2,3] | [1,2,4] |
输入数组表示数字 123。
示例 2:
输入 | 输出 |
---|---|
digits = [4,3,2,1] | [4,3,2,2] |
解释:输入数组表示数字 4321。
示例 3:
输入 | 输出 |
---|---|
digits = [0] | [1] |
解题思路
直接使用数组解题,首先从数组末尾开始遍历,如果末尾数字加1之后对10取余不为0,则说明没有进位,可以直接返回数组;如果为0,说明有进位,则继续向前遍历,然后加1,判断是否有进位,如果遍历结束后仍有进位,则在最后的数组首部加入1,实现进位。
代码
// 加一:数学
class Solution {
public int[] plusOne(int[] digits) {
for (int i = digits.length - 1; i >= 0; i--) {//从数组末尾开始遍历
digits[i]++;
digits[i] = digits[i] % 10;//让数字自增,然后判断是否有进位
if (digits[i] != 0) return digits;//没有进位则直接输出数组,有进位则继续执行循环条件
}
digits = new int[digits.length + 1];//如果遍历完了数字,仍存在进位,则在数组首部加1
digits[0] = 1;
return digits;
}
}
时间复杂度为O(n),n为数组长度
空间复杂度为O(1)
第100题 相同的树/font>
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入 | 输出 |
---|---|
p = [1,2,3], q = [1,2,3] | True |
示例 2:
输入 | 输出 |
---|---|
p = [1,2] | false |
示例 3:
输入 | 输出 |
---|---|
p = [1,2,1], q = [1,1,2] | false |
解题思路
本题使用深度搜索,比较两棵树各对应节点的值。
代码
// 相同的树:dfs
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
} else if (p == null || q == null) {
return false;
} else if (p.val != q.val) {
return false;
} else {
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
}
时间复杂度为O(min(m,n)),m,n为两棵树的节点数
空间复杂度为O(min(m,n))
第118题 杨辉三角
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例 1:
输入 | 输出 |
---|---|
5 | [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] |
解题思路
杨辉三角有一个规律,就是每一行的列数与当前的行数相同,还有规律就是每一行的第一列和最后一列都为1,其余列的值等于同一列上的上一行的值加上前一个左上角的数字。
代码
// 杨辉三角:数组
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();//建立一个数组
for (int i = 0; i < numRows; ++i) {//建立每一行
List<Integer> row = new ArrayList<Integer>();//建立一个一维数组
for (int j = 0; j <= i; ++j) {//对应行数有相应的列数,j为列数
if (j == 0 || j == i) {
row.add(1);//每一行第一个数字和最后一个数字都是1
} else {
row.add(ret.get(i - 1).get(j - 1) + ret.get(i - 1).get(j));//每一行除了第一列和最后一列数字以外,其余列的值等于它同一列的前一行的值加上上一列上一行的值
}
}
ret.add(row);
}
return ret;
}
}
时间复杂度为O(
n
u
m
R
o
w
s
2
numRows^2
numRows2),给定数字的平方。
空间复杂度为O(1)
第119题 杨辉三角 II
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例 1:
输入 | 输出 |
---|---|
3 | [1,3,3,1] |
解题思路
利用数学知识,当前所求的数=前一个数乘上给定数字减去所求数的列数加1,然后再除去所求数的列数,就能得到结果
代码
// 杨辉三角 II:数学
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> row = new ArrayList<Integer>();
row.add(1);//第一列都为1
for (int i = 1; i <= rowIndex; ++i) {
row.add((int) ((long) row.get(i - 1) * (rowIndex - i + 1) / i));//拿3举例,第2列为第一列的值1乘上3减索引1加1的值等于3,再除以索引1,得到最后值为3,第3列为第二列的值3乘3减索引2加1的值为6,再除以索引2,得到最后的值为3
}
return row;
}
}
时间复杂度为O(rowIndex),rowIndex为给定的行数
空间复杂度为O(1)
第125题 验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入 | 输出 |
---|---|
“A man, a plan, a canal: Panama” | true |
示例 2:
输入 | 输出 |
---|---|
“race a car” | false |
解题思路
建立双指针,一个从头遍历,一个从尾遍历,遇到非数字或字符的就直接移动指针,如果左右指针所指的字符相等,则同时向右向左移动指针,如果左指针大于右指针,则该字符串是回文串,如果指针所指字符不相等,则说明不是回文串
代码
// 验证回文串:双指针
class Solution {
public boolean isPalindrome(String s) {
int n = s.length();
int left = 0, right = n - 1;
while (left < right) {
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
++left;
}
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
--right;
}//判断左右指针所指是否为数字或字符,如果不是则移动指针
if (left < right) {
if (Character.toLowerCase(s.charAt(left)) !=Character.toLowerCase(s.charAt(right))) {
return false;
}//如果在左右指针索引不相等的情况下,所指字符不一致,则说明不是回文串
++left;
--right;
}//如果相等则同时移动指针
}
return true;
}
}
时间复杂度为O(s),s为字符串的长度
空间复杂度为O(1)
第171题 Excel表列序号
给定一个Excel表格中的列名称,返回其相应的列序号。
例如,
A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
...
示例 1:
输入 | 输出 |
---|---|
“A” | 1 |
示例 2:
输入 | 输出 |
---|---|
“AB” | 28 |
示例 3:
输入 | 输出 |
---|---|
“ZY” | 701 |
解题思路
遍历字符串,取每个字母,每取一次字符,将其转换为数字后加上原结果乘26的数值,直到遍历完字符串
代码
// Excel表列序号:字符串
class Solution {
public int titleToNumber(String s) {
int ans = 0;
for(int i=0;i<s.length();i++) {
int num = s.charAt(i) - 'A' + 1;
ans = ans * 26 + num;
}
return ans;
}
}
时间复杂度为O(s),s为字符串长度
空间复杂度为O(1)
第191题 位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入 | 输出 |
---|---|
00000000000000000000000000001011 | 3 |
输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。
示例 2:
输入 | 输出 |
---|---|
00000000000000000000000010000000 | 1 |
输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。
示例 3:
输入 | 输出 |
---|---|
11111111111111111111111111111101 | 31 |
输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。
解题思路
运用位运算求解,让数字与比它小一的数字进行&操作,能够将数字右边第1个1变成0,然后用ret记录一次,再循环进行&操作,直到数字变成0
代码
// 位1的个数:位运算
public class Solution {
public int hammingWeight(int n) {
int ret = 0;
while (n != 0) {
n &= n - 1;//把二进制低位1变成0,如6=110,6&6-1即110&101=100,把第二位的1变成了0
ret++;//记录一个1
}
return ret;
}
}
时间复杂度为O(log n),n为二进制中1的的个数
空间复杂度为O(1)
第202题 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 true ;不是,则返回 false 。
示例 1:
输入 | 输出 |
---|---|
19 | true |
解释:
1² + 9² = 82
8² + 2² = 68
6² + 8² = 100
1² + 0² + 0² = 1
示例 2:
输入 | 输出 |
---|---|
n = 2 | false |
解题思路
本题利用双指针解题,如果快慢指针相等,则说明进入了循环,代表数字永远在循环中,不是快乐数,如果慢指针执行getNext操作后,得到了1,则说明原数字是快乐数。
代码
// 快乐数:双指针
class Solution {
public int getNext(int n) {
int totalSum = 0;
while (n > 0) {
int d = n % 10;
n = n / 10;
totalSum += d * d;
}//得到新数字
return totalSum;//返回新数字
}
public boolean isHappy(int n) {
int slowRunner = n;
int fastRunner = getNext(n);
while (fastRunner != 1 && slowRunner != fastRunner) {//判断是否已经为快乐数或者快慢指针已经相等
slowRunner = getNext(slowRunner);//慢指针进行一次getNext操作
fastRunner = getNext(getNext(fastRunner));//快指针执行两次getNext操作,如果快慢指针相等,则说明是一个环,代表数字永远不会等于单个1
}
return fastRunner == 1;//当数字等于1时,则代表原数字是快乐数
}
}
时间复杂度为O(log n),n为慢指针循环执行次数
空间复杂度为O(1)
第219题 存在重复元素 II
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
示例 1:
输入 | 输出 |
---|---|
nums = [1,2,3,1], k = 3 | true |
示例 2:
输入 | 输出 |
---|---|
nums = [1,0,1,1], k = 1 | true |
示例 3:
输入 | 输出 |
---|---|
nums = [1,2,3,1,2,3], k = 2 | false |
解题思路
遍历数组,如果遇到了同样的数,则返回true,否则将数字加入哈希表中,如果哈希表的长度超过了给定值,则将最开始的元素删除,因为即使再出现所删除的数,它们的距离也已经超过了给定值,不符合要求。
代码
// 存在重复元素 II:哈希表
public boolean containsNearbyDuplicate(int[] nums, int k) {
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; ++i) {
if (set.contains(nums[i])) return true;//判断数组中是否存在同样的数
set.add(nums[i]);//如果没有则将数存储
if (set.size() > k) {//如果哈希表的大小大于给定值,则移除开始的元素
set.remove(nums[i - k]);
}
}
return false;
}
时间复杂度为O(n),n为数组长度
空间复杂度为O(min(n,k)),哈希表存储的元素个数
第228题 汇总区间
给定一个无重复元素的有序整数数组 nums 。
返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表。也就是说,nums 的每个元素都恰好被某个区间范围所覆盖,并且不存在属于某个范围但不属于 nums 的数字 x 。
列表中的每个区间范围 [a,b] 应该按如下格式输出:
“a->b” ,如果 a != b
“a” ,如果 a == b
示例 1:
输入 | 输出 |
---|---|
nums = [0,1,2,4,5,7] | [“0->2”,“4->5”,“7”] |
解释:区间范围是:
[0,2] --> “0->2”
[4,5] --> “4->5”
[7,7] --> “7”
示例 2:
输入 | 输出 |
---|---|
nums = [0,2,3,4,6,8,9] | [“0”,“2->4”,“6”,“8->9”] |
解释:区间范围是:
[0,0] --> “0”
[2,4] --> “2->4”
[6,6] --> “6”
[8,9] --> “8->9”
解题思路
遍历数组,当前后数相差1时,则继续遍历,直到前后差值不为1,然后将开始遍历的位置当做左边界,遍历到的前一个位置当做右边界,如果遍历过程中左右边界相等,则直接插入这个数字做为单个字符串。
代码
// 汇总区间:数组遍历
class Solution {
public List<String> summaryRanges(int[] nums) {
List<String> ret = new ArrayList<String>();
int i = 0;
int n = nums.length;
while (i < n) {
int low = i;//low为左边界
i++;
while (i < n && nums[i] == nums[i - 1] + 1) {
i++;
}//当前后元素只相差1时,继续遍历
int high = i - 1;//high为右边界
StringBuffer temp = new StringBuffer(Integer.toString(nums[low]));
if (low < high) {
temp.append("->");
temp.append(Integer.toString(nums[high]));
}//如果左边界小于右边界,则在左边界与右边界之间加入->
ret.add(temp.toString());//如果左边界不小于右边界,则直接加入单个字符
}
return ret;
}
}
时间复杂度为O(n),n为数组长度
空间复杂度为O(1)