剑指Offer
文章目录
-
- 剑指Offer
-
-
- ⭐[剑指 Offer 03. 数组中重复的数字](https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)
- [剑指 Offer 04. 二维数组中的查找](https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/)
- [剑指 Offer 05. 替换空格](https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/)
- [剑指 Offer 06. 从尾到头打印链表](https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/)
- [剑指 Offer 07. 重建二叉树](https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/)
- ⭐[剑指 Offer 09. 用两个栈实现队列](https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/)
- ⭐⭐[剑指 Offer 10- I. 斐波那契数列](https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/)
- [剑指 Offer 10- II. 青蛙跳台阶问题](https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/)
- ⭐⭐[剑指 Offer 11. 旋转数组的最小数字](https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/)
- ⭐[剑指 Offer 12. 矩阵中的路径](https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/)
- ⭐⭐[剑指 Offer 13. 机器人的运动范围](https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/)
- ⭐⭐[剑指 Offer 14- I. 剪绳子](https://leetcode-cn.com/problems/jian-sheng-zi-lcof/)
- ⭐[剑指 Offer 14- II. 剪绳子 II](https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/)
- [剑指 Offer 15. 二进制中1的个数](https://leetcode-cn.com/problems/er-jin-zhi-zhong-1de-ge-shu-lcof/)
- ⭐⭐[剑指 Offer 16. 数值的整数次方](https://leetcode-cn.com/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/)
- ⭐⭐[剑指 Offer 17. 打印从1到最大的n位数](https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/)
- [剑指 Offer 18. 删除链表的节点](https://leetcode-cn.com/problems/shan-chu-lian-biao-de-jie-dian-lcof/)
- [剑指 Offer 20. 表示数值的字符串](https://leetcode-cn.com/problems/biao-shi-shu-zhi-de-zi-fu-chuan-lcof/)
- [剑指 Offer 21. 调整数组顺序使奇数位于偶数前面](https://leetcode-cn.com/problems/diao-zheng-shu-zu-shun-xu-shi-qi-shu-wei-yu-ou-shu-qian-mian-lcof/)
- [剑指 Offer 22. 链表中倒数第k个节点](https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/)
- ⭐[剑指 Offer 24. 反转链表](https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/)
- [剑指 Offer 25. 合并两个排序的链表](https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof/)
- ⭐⭐⭐[剑指 Offer 26. 树的子结构](https://leetcode-cn.com/problems/shu-de-zi-jie-gou-lcof/)
- ⭐⭐[剑指 Offer 27. 二叉树的镜像](https://leetcode-cn.com/problems/er-cha-shu-de-jing-xiang-lcof/)
- [剑指 Offer 28. 对称的二叉树](https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/)
- ⭐[剑指 Offer 29. 顺时针打印矩阵](https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/)
- [剑指 Offer 30. 包含min函数的栈](https://leetcode-cn.com/problems/bao-han-minhan-shu-de-zhan-lcof/)
- ⭐[剑指 Offer 31. 栈的压入、弹出序列](https://leetcode-cn.com/problems/zhan-de-ya-ru-dan-chu-xu-lie-lcof/)
- [面试题32 - I. 从上到下打印二叉树](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/)
- [剑指 Offer 32 - II. 从上到下打印二叉树 II](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/)
- [剑指 Offer 32 - III. 从上到下打印二叉树 III](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/)
- ⭐⭐⭐[剑指 Offer 33. 二叉搜索树的后序遍历序列](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/)
- ⭐⭐[剑指 Offer 34. 二叉树中和为某一值的路径](https://leetcode-cn.com/problems/er-cha-shu-zhong-he-wei-mou-yi-zhi-de-lu-jing-lcof/)
- [剑指 Offer 35. 复杂链表的复制](https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/)
- [剑指 Offer 37. 序列化二叉树](https://leetcode-cn.com/problems/xu-lie-hua-er-cha-shu-lcof/)
- ⭐[剑指 Offer 38. 字符串的排列](https://leetcode-cn.com/problems/zi-fu-chuan-de-pai-lie-lcof/)
- [剑指 Offer 39. 数组中出现次数超过一半的数字](https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/)
- ⭐[剑指 Offer 40. 最小的k个数](https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/)
- [剑指 Offer 42. 连续子数组的最大和](https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/)
- [剑指 Offer 46. 把数字翻译成字符串](https://leetcode-cn.com/problems/ba-shu-zi-fan-yi-cheng-zi-fu-chuan-lcof/)
- [剑指 Offer 47. 礼物的最大价值](https://leetcode-cn.com/problems/li-wu-de-zui-da-jie-zhi-lcof/)
- ⭐⭐⭐[剑指 Offer 48. 最长不含重复字符的子字符串](https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/)
- ⭐⭐[剑指 Offer 49. 丑数](https://leetcode-cn.com/problems/chou-shu-lcof/)
- [剑指 Offer 50. 第一个只出现一次的字符](https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/)
- [剑指 Offer 52. 两个链表的第一个公共节点](https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/)
- ⭐[剑指 Offer 53 - I. 在排序数组中查找数字 I](https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/)
- ⭐[剑指 Offer 53 - II. 0~n-1中缺失的数字](https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/)
- [剑指 Offer 54. 二叉搜索树的第k大节点](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/)
- [剑指 Offer 55 - I. 二叉树的深度](https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/)
- ⭐⭐[剑指 Offer 55 - II. 平衡二叉树](https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/)
- ⭐⭐[剑指 Offer 56 - I. 数组中数字出现的次数](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/)
- ⭐⭐[剑指 Offer 56 - II. 数组中数字出现的次数 II](https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/)
- [剑指 Offer 57. 和为s的两个数字](https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/)
- ⭐⭐⭐[剑指 Offer 57 - II. 和为s的连续正数序列](https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/)
- [剑指 Offer 58 - I. 翻转单词顺序](https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/)
- [剑指 Offer 58 - II. 左旋转字符串](https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/)
- [剑指 Offer 59 - II. 队列的最大值](https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/)
- ⭐[剑指 Offer 60. n个骰子的点数](https://leetcode-cn.com/problems/nge-tou-zi-de-dian-shu-lcof/)
- ⭐⭐[剑指 Offer 61. 扑克牌中的顺子](https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/)
- ⭐⭐[剑指 Offer 62. 圆圈中最后剩下的数字](https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/)
- [剑指 Offer 63. 股票的最大利润](https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/)
- [剑指 Offer 64. 求1+2+…+n](https://leetcode-cn.com/problems/qiu-12n-lcof/)
- [剑指 Offer 65. 不用加减乘除做加法](https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/)
- [剑指 Offer 66. 构建乘积数组](https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/)
- [剑指 Offer 68 - I. 二叉搜索树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-lcof/)
- [剑指 Offer 68 - II. 二叉树的最近公共祖先](https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/)
-
⭐剑指 Offer 03. 数组中重复的数字
找出数组中重复的数字。在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
// 如果用set或者map的话
// Time:O(n)
// Space:O(n)
// 值: 0 2 1 3 3
// 下标: 0 1 2 3 4
// 对于每个数字nums[i]如果这个数字 nums[i] 不等于其 下标 i的话,则将这个数字放到 nums[i]这个下标上,如果交换的时候发现两者相同则直接返回。
class Solution {
public int findRepeatNumber(int[] nums) {
for (int i = 0; i < nums.length; i++) {
while (nums[i] != i) {
if (nums[i] == nums[nums[i]]) {
return nums[i];
}
swap(nums, i, nums[i]);
}
}
return -1;
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
// Time:O(n)
// Space:O(1)
剑指 Offer 04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0) return false;
int m = matrix.length, n = matrix[0].length;
int row = 0, col = n - 1;
while (row < m && col >= 0) {
if (matrix[row][col] == target) {
return true;
} else if (matrix[row][col] < target) {
row++;
} else {
col--;
}
}
return false;
}
}
// Time:O(m+n)
// Space:O(1)
剑指 Offer 05. 替换空格
难度简单211
请实现一个函数,把字符串 s
中的每个空格替换成"%20"。
class Solution {
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ') {
sb.append("%20");
} else {
sb.append(c);
}
}
return sb.toString();
}
}
// Time:O(n)
// Space:O(n)
剑指 Offer 06. 从尾到头打印链表
难度简单234
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
// 1. 反转链表,然后正常放入值
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public int[] reversePrint(ListNode head) {
ListNode dummy = new ListNode(0);
ListNode p = head;
int len = 0;
while (p != null) {
len++;
ListNode temp = p.next;
p.next = dummy.next;
dummy.next = p;
p = temp;
}
int[] res = new int[len];
int i = 0;
while (dummy.next != null) {
res[i++] = dummy.next.val;
dummy = dummy.next;
}
return res;
}
}
// 2. 第一个值放到最后一个位置,第二个值放到倒数第二个位置,以此类推
class Solution {
public int[] reversePrint(ListNode head) {
int len = 0;
ListNode p = head;
while (p != null) {
len++;
p = p.next;
}
int[] res = new int[len];
p = head;
for (int i = len - 1; i >= 0; i--) {
res[i] = p.val;
p = p.next;
}
return res;
}
}
// Time:O(n)
// Space:O(n)
剑指 Offer 07. 重建二叉树
难度中等663
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return helper(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}
private TreeNode helper (int[] preorder, int pre_left, int pre_right, int[] inorder, int in_left, int in_right) {
if (pre_left > pre_right || in_left > in_right) return null;
TreeNode root = new TreeNode(preorder[pre_left]);
int ind = 0;
for (int i = in_left; i <= in_right; i++) {
if (inorder[i] == preorder[pre_left]) {
ind = i;
break;
}
}
int left_size = ind - 1 - in_left + 1, right_size = in_right - (ind + 1) + 1;
root.left = helper(preorder, pre_left + 1, pre_left + left_size, inorder, in_left, in_left + left_size - 1);
root.right = helper(preorder, pre_right - right_size + 1, pre_right, inorder, in_right - right_size + 1, in_right);
return root;
}
}
// Time: O(n+nlgn)->O(nlgn)
// Space:O(lgn)
⭐剑指 Offer 09. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail
和 deleteHead
,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead
操作返回 -1 )
class CQueue {
private Deque<Integer> stack1;
private Deque<Integer> stack2;
public CQueue() {
stack1 = new LinkedList<>();
stack2 = new LinkedList<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if (stack2.isEmpty()) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
if (stack2.isEmpty()) {
return -1;
} else {
return stack2.pop();
}
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
⭐⭐剑指 Offer 10- I. 斐波那契数列
写一个函数,输入 n
,求斐波那契(Fibonacci)数列的第 n
项(即 F(N)
)。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
class Solution {
public int fib(int n) {
if (n == 0 || n == 1) return n;
int a = 0, b = 1;
for (int i = 2; i <= n; i++) {
int c = (a + b) % 1000000007;
a = b;
b = c;
}
return b;
}
}
矩阵快速幂
class Solution {
static final int MOD = 1000000007;
public int fib(int n) {
if (n < 2) {
return n;
}
int[][] q = {
{
1, 1}, {
1, 0}};
int[][] res = pow(q, n - 1);
return res[0][0];
}
public int[][] pow(int[][] a, int n) {
int[][] ret = {
{
1, 0}, {
0, 1}};
while (n > 0) {
if ((n & 1) == 1) {
ret = multiply(ret, a);
}
n >>= 1; // n /= 2
a = multiply(a, a);
}
return ret;
}
public int[][] multiply(int[][] a, int[][] b) {
int[][] c = new int[2][2];
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
c[i][j] = (int) (((long) a[i][0] * b[0][j] + (long) a[i][1] * b[1][j]) % MOD);
}
}
return c;
}
}
剑指 Offer 10- II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n
级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
class Solution {
public int numWays(int n) {
if (n == 0 || n == 1) return 1;
int[] dp = new int[n + 1];
int a = 1, b = 1, c = 2;
for (int i = 2; i <= n; i++) {
c = (a + b) % 1000000007;
a = b;
b = c;
}
return c;
}
}
⭐⭐剑指 Offer 11. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
给你一个可能存在 重复 元素值的数组 numbers
,它原来是一个升序排列的数组,并按上述情形进行了一次旋转。请返回旋转数组的最小元素。例如,数组 [3,4,5,1,2]
为 [1,2,3,4,5]
的一次旋转,该数组的最小值为1。
// 注意不能用mid与left进行比较进行区间缩小
class Solution {
public int minArray(int[] numbers) {
int len = numbers.length;
int left = 0, right = len - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (numbers[mid] > numbers[right]) {
// [mid + 1, right]
left = mid + 1;
} else if (numbers[mid] < numbers[right]) {
// [left, mid]
right = mid;
} else {
// 若想等,只能将right缩小,无法确定具体区间
// 示例一 [1, 0, 1, 1, 1][1,0,1,1,1] :旋转点 x = 1x=1 ,因此 m=2,m=2 在 右排序数组 中。
// 示例二 [1, 1, 1, 0, 1][1,1,1,0,1] :旋转点 x = 3x=3 ,因此 m=2,m=2 在 左排序数组 中。
right--;
}
}
return numbers[left];
}
}
// Time:O(lgn)
// Space:O(1)
⭐剑指 Offer 12. 矩阵中的路径
给定一个 m x n
二维字符网格 board
和一个字符串单词 word
。如果 word
存在于网格中,返回 true
;否则,返回 false
。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
class Solution {
public boolean exist(char[][] board, String word) {
if (board == null || board.length == 0 || board[0].length == 0) return false;
int m = board.length, n = board[0].length;
boolean[][] visited = new boolean[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(visited, board, i, j, word, 0)) {
return true;
}
}
}
return false;
}
private boolean dfs(boolean[][] visited, char[][] board, int i, int j, String word, int index) {
if ((i < 0 || i >= board.length) || (j < 0 || j >= board[0].length) || visited[i][j] || board[i][j] != word.charAt(index))
return false;
if (index == word.length() - 1) {
return true;
}
visited[i][j] = true;
boolean find = dfs(visited, board, i + 1, j, word, index + 1)
|| dfs(visited, board, i - 1, j, word, index + 1)
|| dfs(visited, board, i, j + 1, word, index + 1)
|| dfs(visited, board, i, j - 1, word, index + 1);
visited[i][j] = false;
return find;
}
}
⭐⭐剑指 Offer 13. 机器人的运动范围
难度中等436
地上有一个m行n列的方格,从坐标 [0,0]
到坐标 [m-1,n-1]
。一个机器人从坐标 [0, 0]
的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
class Solution {
public int movingCount(int m, int n, int k) {
if (m == 0 || n == 0) return 0;
boolean[][] vis = new boolean[m][n];
return dfs(vis, 0, 0, k);
}
private int dfs(boolean[][] vis, int i, int j, int k) {
if ((i < 0 || i >= vis.length) || (j < 0 || j >= vis[0].length) || vis[i][j] || (i / 10 + i % 10 + j / 10 + j % 10) > k) return 0;
vis[i][j] = true;
return 1 + dfs(vis, i + 1, j, k) + dfs(vis, i, j + 1, k);
}
}
⭐⭐剑指 Offer 14- I. 剪绳子
给你一根长度为 n
的绳子,请把绳子剪成整数长度的 m
段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1]
。请问 k[0]*k[1]*...*k[m-1]
可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
动态规划
class Solution {
public int cuttingRope(int n) {
// dp[i] 表示长度为i至少剪一刀的最大乘积
int[] dp = new int[n + 1];
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= i - 1; j++) {
dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
}
}
return dp[n];
}
}
贪心
算法流程:
当 n ≤ 3 n \leq 3 n≤3 时,按照规则应不切分,但由于题目要求必须剪成 m>1 段,因此必须剪出一段长度为 1 的绳子,即返回 n - 1 。
当 n > 3 n n>3n n>3n 时,求 n 除以 3 的 整数部分 a 和 余数部分bb (即 n = 3a+b ),并分为以下三种情况:
当 b = 0 时,直接返回 3 a 3^a 3a
当 b = 1 时,要将一个 1 + 31+3 转换为 2+22+2,因此返回 3 a − 1 × 4 3^{a-1} \times 4 3a−1×4
当 b = 2 时,返回 3 a × 2 3^a \times 2 3a×2
class Solution {
public int cuttingRope(int n) {
if (n <= 3) return n - 1;
int res = 1;
while (n > 4) {
res = res * 3;
n -= 3;
}
res *= n;
return res;
}
}
⭐剑指 Offer 14- II. 剪绳子 II
给你一根长度为 n
的绳子,请把绳子剪成整数长度的 m
段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m - 1]
。请问 k[0]*k[1]*...*k[m - 1]
可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
// 1. dp
class Solution {
public int cuttingRope(int n) {
// dp[i] 表示总长度为 i 能够得到的最大乘积
// 最后一段可以长度 j 为 1 , 2, ..., i - 2
// 对于前面长度为 i - j的话可以剪,也可以不剪
// 那么结果就是 max(dp[i], max(j * dp[i - j], j * (i - j)))
// 也就是 1 * dp[i - 1], 2 * d[i - 2], ... , (i - 2) * dp[2]
int[] dp = new int[n + 1];
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j <= i - 2; j++) {
dp[i] = Math.max(dp[i], Math.max(j * dp[i - j], j * (i - j)));
}
}
return dp[n];
}
}
class Solution {
public int cuttingRope(int n) {
if (n <= 3) return n - 1;
long res = 1;
while(n > 4){
res = res * 3 % 1000000007;
n -= 3;
}
return (int)(res * n % 1000000007);
}
}
剑指 Offer 15. 二进制中1的个数
难度简单215
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为 汉明重量).)。
class Solution {
// 1. 检查第i位时,将n与2^i次方进行与运算,如果与完之后等于2^i,说明该位置是1,如果与完之后等于0,说明该位置是0
// 1 0 0 1 0
// 0 0 0 1 0
public int hammingWeight(int n) {
int cnt = 0;
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) != 0) cnt++;
}
return cnt;
}
// 2. 每次检查最低位是不是1,是则计数,每次判断完最低位之后都要右移一位
public int hammingWeight_1(int n) {
int cnt = 0;
for (int i = 0; i < 32; i++) {
if ((n & 1) == 1) cnt++;
n = n >> 1;
}
return cnt;
}
// 3. 通过n & (n-1)来将n最低位的1置为0,直到n等于0为止
public int hammingWeight_2(int n) {
int cnt = 0;
while (n != 0) {
n = n & (n - 1);
cnt++;
}
return cnt;
}
}
⭐⭐剑指 Offer 16. 数值的整数次方
难度中等254
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x^n)。不得使用库函数,同时不需要考虑大数问题。
快速幂 + 递归
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;
// n / 2 + n / 2 + n % 2
double half = myPow(x, n / 2);
double mod = myPow(x, n % 2);
return half * half * mod;
}
}
// Time:O(lgn)
// Space:O(lgn)
快速幂 + 迭代
class Solution {
public double myPow(double x, int n) {
if (n == 0) return 1.0;
long b = n; // 负数最小值的绝对值超出int范围,所以用更大容量防止溢出
if (b < 0) {
x = 1 / x;
b = -b;
}
double res = 1.0;
while (b > 0) {
if ((b & 1