剑指 Offer 10- II. 青蛙跳台阶问题
跟斐波那契一样解法
- 递归 超时orz…
class Solution {
public int numWays(int n) {
if (n == 0 || n == 1) return 1;
return numWays(n - 1) + numWays(n - 2);
}
}
- 动态规划
class Solution {
public int numWays(int n) {
if (n == 0 || n == 1) return 1;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
}
return dp[n];
}
}
- 优化:节省空间
class Solution {
public int numWays(int n) {
if (n == 0 || n == 1) return 1;
int a = 1, b = 1, c = 0;
for (int i = 2; i <= n; i++) {
c = (a + b) % 1000000007;
a = b;
b = c;
}
return c;
}
}
剑指 Offer 11. 旋转数组的最小数字
- 直接升序排序,取数组索引为 0 的值
class Solution {
public int minArray(int[] numbers) {
Arrays.sort(numbers);
return numbers[0];
}
}
- 据题意,数组为升序数组的【旋转】,那么我们只需遍历寻找第一个【当前数大于后一位的数】返回即可;如果没找到,说明数组为原地【旋转】(即不变)升序排序,返回数组第一个数
class Solution {
public int minArray(int[] numbers) {
for (int i = 0; i < numbers.length - 1; i++) {
if (numbers[i] > numbers[i + 1]) {
return numbers[i + 1];
}
}
return numbers[0];
}
}
剑指 Offer 12. 矩阵中的路径
剑指 Offer 13. 机器人的运动范围
剑指 Offer 14- I. 剪绳子
剑指 Offer 14- II. 剪绳子 II
剑指 Offer 15. 二进制中1的个数
- 将十进制数字转二进制字符串,API:Integer.toBinaryString();
然后遍历字符串,统计 1 的个数
public class Solution {
public int hammingWeight(int n) {
int count = 0;
String str = Integer.toBinaryString(n);
for(char c : str.toCharArray()) {
if (c == '1') count++;
}
return count;
}
}
- API:Integer.bitCount(n); 统计十进制 n,二进制的 1 的个数
public class Solution {
public int hammingWeight(int n) {
return Integer.bitCount(n);
}
}
- 【推荐】位运算:将二进制数字 n 无符号右移一位 n >>> 1,每次将 n & 1
若 n & 1 = 0,则 n 二进制 最右一位 为 0
若 n & 1 = 1,则 n 二进制 最右一位 为 1
右移相当于将二进制最后一位舍去
public class Solution {
public int hammingWeight(int n) {
int count = 0;
while (n != 0) {
if ((n & 1) == 1) count++;
n = n >>> 1;
}
return count;
}
}
剑指 Offer 16. 数值的整数次方
- 常规做法,超时orz
class Solution {
public double myPow(double x, int n) {
if (n == 0) return 1.0;
double res = 1;
for (int i = 0; i < Math.abs(n); i++) {
res *= x;
}
if (n < 0) return 1.0 / res;
return res;
}
}
- API:Math.pow()
class Solution {
public double myPow(double x, int n) {
return Math.pow(x, n);
}
}
- 但题意要求:不得使用库函数,所以要采用快速幂算法(递归或循环)解决
快速幂原理:每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变
快速幂算法将幂次运算由 O(n) 的复杂度简化到 O(logn)
- 位运算符的使用:
n & 1:判断奇数还是偶数
n >> 1:n / 2的1次方
class Solution {
public double myPow(double x, int n) {
if (n == 0) return 1;
if (n == 1) return x;
if (n == -1) return 1 / x;
double half = myPow(x, n >> 1);
double rest = myPow(x, n & 1);
return half * half * rest;
}
}
剑指 Offer 18. 删除链表的节点
- 常规题,但需要注意边界问题(例如:要删除的节点为第一个节点)
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head.val == val) return head.next;
ListNode cur = head;
while (cur.next.val != val) {
cur = cur.next;
}
cur.next = cur.next.next;
return head;
}
}