劍指OFFER
1 陣列
03. 陣列中重複的數字
https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
在一個長度為 n 的陣列 nums 裡的所有數字都在 0~n-1 的範圍內。陣列中某些數字是重複的,但不知道有幾個數字重複了,也不知道每個數字重複了幾次。請找出陣列中任意一個重複的數字。
1)Hash or Set
2)原地交換
/**
* 原地交換 : o(n)
*/
public int findRepeatNumber(int[] nums) {
int i = 0, n = nums.length;
while (i < n) {
if (nums[i] == i) {
i++;
continue;
}
if (nums[nums[i]] == nums[i]) return nums[i];
// swap
int tmp = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = tmp;
}
return -1;
}
04. 二維陣列中的查詢
https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
在一個 n * m 的二維陣列中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個高效的函式,輸入這樣的一個二維陣列和一個整數,判斷陣列中是否含有該整數。
1)BST
/**
* BST: 右上角開始 O(M+N)
*/
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix.length < 1) {
return false;
}
int m = 0, n = matrix[0].length - 1;
while (n >= 0 && m < matrix.length) {
if (matrix[m][n] == target) {
return true;
} else if (matrix[m][n] > target) {
n--;
} else {
m++;
}
}
return false;
}
11. 旋轉陣列的最小數字
https://leetcode-cn.com/problems/xuan-zhuan-shu-zu-de-zui-xiao-shu-zi-lcof/
輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如,陣列 [3,4,5,1,2] 為 [1,2,3,4,5] 的一個旋轉,該陣列的最小值為1。
1)線性查詢
2)二分法
/**
* 二分 : o(logn)
*/
public int minArray(int[] numbers) {
int i = 0, j = numbers.length - 1;
while (i < j) {
int m = (i + j) / 2;
if (numbers[m] > numbers[j]) i = m + 1;
else if (numbers[m] < numbers[j]) j = m;
else j--;
}
return numbers[i];
}
39. 陣列中出現次數超過一半的數字
https://leetcode-cn.com/problems/shu-zu-zhong-chu-xian-ci-shu-chao-guo-yi-ban-de-shu-zi-lcof/
陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。
1)Hash
2)排序:陣列中點一定是眾數
3)摩爾投票法
/**
* 摩爾投票 : o(n)
*/
public int majorityElement(int[] nums) {
int votes = 0, x = 0;
for (int n : nums) {
// 投票數為0,則假設當前n為眾數
if (votes == 0) x = n;
votes += n == x ? 1 : -1;
}
// 驗證 x 是否為眾數
return x;
}
40. 最小的k個數
https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
輸入整數陣列 arr ,找出其中最小的 k 個數。例如,輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。
1)排序 or 快排
/**
* 快排 : o(n)
*/
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0) return new int[0];
partition(arr, 0, arr.length - 1, k);
return Arrays.stream(arr).limit(k).toArray();
}
public void partition(int[] array, int start, int end, int k) {
int p = array[start], i = start, j = end;
while (i < j) {
while (i < j && array[j] >= p) {
j--;
}
array[i] = array[j];
while (i < j && array[i] <= p) {
i++;
}
array[j] = array[i];
}
array[j] = p;
if (j == k - 1) {
return;
} else if (j > k - 1) {
partition(array, start, j - 1, k);
} else {
partition(array, j + 1, end, k);
}
}
2)大頂堆(PriorityQueue)
/**
* 大頂堆 : o(nlogk)
*/
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0) return new int[0];
Queue<Integer> heap = new PriorityQueue<>((o1, o2) -> o2 - o1);
for (int n : arr) {
if (heap.size() < k) {
heap.offer(n);
} else if (heap.peek() > n) {
heap.poll();
heap.offer(n);
}
}
return heap.stream().mapToInt(x -> x).toArray();
}
51. 陣列中的逆序對
https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
53 - I. 在排序陣列中查詢數字 I
https://leetcode-cn.com/problems/zai-pai-xu-shu-zu-zhong-cha-zhao-shu-zi-lcof/
統計一個數字在排序陣列中出現的次數。
/**
* 二分法 : o(logn)
*/
public int search(int[] nums, int target) {
// methodA : 分兩次找出左右邊界
// methodB : 分別找出 target 和 target-1 的右邊界
return binarySearch(nums, target) - binarySearch(nums, target - 1);
}
public int binarySearch(int[] nums, int tar) {
int i = 0, j = nums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (nums[m] <= tar) i = m + 1;
else j = m - 1;
}
return i;
}
53 - II. 0~n-1中缺失的數字
https://leetcode-cn.com/problems/que-shi-de-shu-zi-lcof/
一個長度為n-1的遞增排序陣列中的所有數字都是唯一的,並且每個數字都在範圍0~n-1之內。在範圍0~n-1內的n個數字中有且只有一個數字不在該陣列中,請找出這個數字。
/**
* 二分法 : o(logn)
*/
public int missingNumber(int[] nums) {
int l = 0, r = nums.length - 1;
while (l <= r) {
int m = l + (r - l) / 2;
if (nums[m] == m) {
l = m + 1;
} else {
r = m - 1;
}
}
return l - 1;
}
56 - I. 陣列中數字出現的次數
https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/
Medium : marked
一個整型陣列 nums 裡除兩個數字之外,其他數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。
/**
* 異或和分組 : o(n)
*/
public int[] singleNumbers(int[] nums) {
int ret = 0;
for (int n : nums) {
ret ^= n;
}
// 從右往左找出異或結果不為1的位
int d = 1;
while ((d & ret) == 0) {
d <<= 1;
}
int[] res = new int[2];
// 分組並異或
for (int n : nums) {
if ((d & n) == 0) {
res[0] ^= n;
} else {
res[1] ^= n;
}
}
return res;
}
56 - II. 陣列中數字出現的次數 II
https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-ii-lcof/
Medium : marked
在一個陣列 nums 中除一個數字只出現一次之外,其他數字都出現了三次。請找出那個只出現一次的數字。
/**
* 有限狀態自動機
*/
public int singleNumber(int[] nums) {
int ones = 0, twos = 0;
for(int num : nums){
ones = ones ^ num & ~twos;
twos = twos ^ num & ~ones;
}
return ones;
}
/**
* hashMap
*/
57 - I. 和為s的兩個數字
https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/
輸入一個遞增排序的陣列和一個數字s,在陣列中查詢兩個數,使得它們的和正好是s。如果有多對數字的和等於s,則輸出任意一對即可。
/**
* 碰撞雙指標 : o(n)
*/
public int[] twoSum(int[] nums, int target) {
int l = 0, r = nums.length - 1;
while (l < r) {
int s = nums[l] + nums[r];
if (s < target) {
l++;
} else if (s == target) {
return new int[]{nums[l], nums[r]};
} else {
r--;
}
}
return new int[0];
}
57 - II. 和為s的連續正數序列
https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/
輸入一個正整數 target ,輸出所有和為 target 的連續正整數序列(至少含有兩個數)。
序列內的數字由小到大排列,不同序列按照首個數字從小到大排列。
/**
* 滑動視窗 : o(n)
*/
public int[][] findContinuousSequence(int target) {
// 左閉右開
int l = 1, r = 1, sum = 0;
List<int[]> res = new ArrayList<>();
while (l <= target / 2) {
if (sum < target) {
sum += r;
// 有邊界右滑
r++;
} else if (sum == target) {
int[] arr = new int[r - l];
for (int i = l; i < r; i++) {
arr[i - l] = i;
}
res.add(arr);
sum -= l;
l++;
} else {
sum -= l;
l++;
}
}
return res.toArray(new int[res.size()][]);
}
59 - I. 滑動視窗的最大值
https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/
給定一個陣列 nums 和滑動視窗的大小 k,請找出所有滑動視窗裡的最大值。
1) 模擬
/**
* 模擬 : o(nk)
*/
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || k <= 0 || nums.length < k) {
return new int[0];
}
int length = nums.length - k + 1;
int[] result = new int[length];
int curMax;
for (int i = 0; i < length; i++) {
curMax = Integer.MIN_VALUE;
for (int j = 0; j < k; j++) {
curMax = Math.max(nums[i+j], curMax);
}
result[i] = curMax;
}
return result;
}
2)單調(雙端)佇列
/**
* 單調佇列 : o(n)
*/
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || k <= 0 || nums.length < k) {
return new int[0];
}
int length = nums.length - k + 1;
int[] res = new int[length];
// 記錄下標,防止重複元素
Deque<Integer> queue = new LinkedList<>();
for (int i = 0; i < nums.length; i++) {
while (!queue.isEmpty() && nums[queue.peekLast()] < nums[i]) {
queue.pollLast();
}
queue.offer(i);
if (i >= k - 1) {
// 形成第一個視窗
if (!queue.isEmpty() && queue.peek() == i - k)
queue.poll();
res[i - k + 1] = nums[queue.peek()];
}
}
return res;
}
59 - II. 佇列的最大值
https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof/
Medium
請定義一個佇列並實現函式 max_value 得到佇列裡的最大值,要求函式max_value、push_back 和 pop_front 的均攤時間複雜度都是O(1)。
1)queue + deque(雙端佇列)
class MaxQueue {
Queue<Integer> queue;
Deque<Integer> deque;
public MaxQueue() {
queue = new LinkedList<>();
deque = new LinkedList<>();
}
public int max_value() {
return deque.isEmpty() ? -1 : deque.peekFirst();
}
public void push_back(int value) {
queue.offer(value);
while(!deque.isEmpty() && deque.peekLast() < value)
deque.pollLast();
deque.offerLast(value);
}
public int pop_front() {
if(queue.isEmpty()) return -1;
if(queue.peek().equals(deque.peekFirst()))
deque.pollFirst();
return queue.poll();
}
}
2 字串
05. 替換空格
https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/
請實現一個函式,把字串 s 中的每個空格替換成"%20"。
1)遍歷新增
50. 第一個只出現一次的字元
https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/
在字串 s 中找出第一個只出現一次的字元。如果沒有,返回一個單空格。 s 只包含小寫字母。
1)Hash
/**
* Hash : o(n)
*/
public char firstUniqChar(String s) {
Map<Character, Boolean> map = new HashMap<>();
char[] array = s.toCharArray();
for (char c : array) {
map.put(c, !map.containsKey(c));
}
for (char c : array) {
if (map.get(c)) return c;
}
return ' ';
}
2)點陣圖
/**
* 點陣圖 : o(n)
*/
public char firstUniqChar(String s) {
int[] map = new int[26];
char[] chars = s.toCharArray();
for (char c : chars) {
map[c - 'a']++;
}
for (char c : chars) {
if (map[c - 'a'] == 1) return c;
}
return ' ';
}
3)有序雜湊表(LinkedHashMap)
58 - I. 翻轉單詞順序
https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/
輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字元的順序不變。為簡單起見,標點符號和普通字母一樣處理。例如輸入字串"I am a student. “,則輸出"student. a am I”。
1)雙指標
2)字串分割
/**
* 雙指標 : o(n)
*/
public String reverseWords(String s) {
// 去除首尾空格
s = s.trim();
int l = s.length() - 1, r = l;
StringBuilder sb = new StringBuilder();
while (l >= 0) {
while (l >= 0 && s.charAt(l) != ' ') {
l--;
}
sb.append(s, l + 1, r + 1).append(" ");
// 跳過空格
while (l >= 0 && s.charAt(l) == ' ') {
l--;
}
r = l;
}
return sb.toString().trim();
}
58 - II. 左旋轉字串
https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
字串的左旋轉操作是把字串前面的若干個字元轉移到字串的尾部。請定義一個函式實現字串左旋轉操作的功能。比如,輸入字串"abcdefg"和數字2,該函式將返回左旋轉兩位得到的結果"cdefgab"。
1)字串切片
public String reverseLeftWords(String s, int n) {
return s.substring(n, s.length()) + s.substring(0, n);
}
2)列表遍歷拼接
public String reverseLeftWords(String s, int n) {
StringBuilder sb = new StringBuilder();
int size = s.length();
for (int i = n; i < n + size; i++) {
sb.append(s.charAt(i % size));
}
return sb.toString();
}
3)原地左移(陣列倒置)
67. 把字串轉換成整數
https://leetcode-cn.com/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/
Medium
寫一個函式 StrToInt,實現把字串轉換成整數這個功能。不能使用 atoi 或者其他類似的庫函式。
/**
* 數學 : o(n)
*/
public int strToInt(String str) {
char[] chars = str.toCharArray();
if (chars.length == 0) return 0;
int i = 0;
// 除去空格
while (chars[i] == ' ') {
i++;
if (i == chars.length) return 0;
}
int res = 0, flag = str.charAt(i) == '-' ? -1 : 1;
if (str.charAt(i) == '-' || str.charAt(i) == '+') i++;
for (int j = i; j < chars.length; j++) {
if (chars[j] < '0' || chars[j] > '9') break;
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && chars[j] > '7')) {
// 越界
return flag == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
res = res * 10 + (chars[j] - '0');
}
return flag * res;
}
3 連結串列
06. 從尾到頭列印連結串列
https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/
輸入一個連結串列的頭節點,從尾到頭反過來返回每個節點的值(用陣列返回)。
1)遞迴
/**
* 遞迴 : o(n)
*/
public int[] reversePrint(ListNode head) {
if (head == null) return new int[0];
List<Integer> list = new ArrayList<>();
recur(head, list);
return list.stream().mapToInt(x -> x).toArray();
}
public void recur(ListNode root, List<Integer> list) {
if (root.next != null) {
recur(root.next, list);
}
list.add(root.val);
}
2)棧
/**
* 棧 : o(n)
*/
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack = new Stack<>();
while (head != null) {
stack.push(head);
head = head.next;
}
int[] res = new int[stack.size()];
while (!stack.isEmpty()) {
res[res.length - stack.size()] = stack.pop().val;
}
return res;
}
52. 兩個連結串列的第一個公共節點
https://leetcode-cn.com/problems/liang-ge-lian-biao-de-di-yi-ge-gong-gong-jie-dian-lcof/
輸入兩個連結串列,找出它們的第一個公共節點。
/**
* 雙指標 : o(m+n)
*/
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode currA = headA, currB = headB;
// 交點在 l1 + l2 + c 處
while (currA != currB) {
currA = currA == null ? headB : currA.next;
currB = currB == null ? headA : currB.next;
}
return currA;
}
4 二叉樹
樹的遍歷方式總體分為兩類:深度優先搜尋(DFS)、廣度優先搜尋(BFS);
常見的 DFS : 先序遍歷(根-左-右)、中序遍歷(左-根-右)、後序遍歷(左-右-根);
常見的 BFS : 層序遍歷(按層遍歷)。
54. 二叉搜尋樹的第k大節點
https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/
給定一棵二叉搜尋樹,請找出其中第k大的節點。
二叉搜尋樹的中序遍歷為遞增序列。
/**
* 中序遍歷的倒序 o(n)
*/
public int kthLargest(TreeNode root, int k) {
this.k = k;
inorder(root);
return res;
}
private int k;
private int res;
public void inorder(TreeNode root) {
if (root == null || k == 0) {
return;
}
// 先找最大
inorder(root.right);
if (--k == 0) {
res = root.val;
return;
}
inorder(root.left);
}
55 - I. 二叉樹的深度
https://leetcode-cn.com/problems/er-cha-shu-de-shen-du-lcof/
輸入一棵二叉樹的根節點,求該樹的深度。從根節點到葉節點依次經過的節點(含根、葉節點)形成樹的一條路徑,最長路徑的長度為樹的深度。
/**
* DFS : 遞迴 or 棧 o(n)
* BFS : 佇列
*/
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
55 - II. 是否為平衡二叉樹
https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/
輸入一棵二叉樹的根節點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意節點的左右子樹的深度相差不超過1,那麼它就是一棵平衡二叉
/**
* DFS : 自底向上後序 o(n)
*/
public boolean isBalanced(TreeNode root) {
return balanced(root) != -1;
}
public int balanced(TreeNode root) {
if (root == null) {
return 0;
}
int left = balanced(root.left);
if (left == -1) {
return -1;
}
int right = balanced(root.right);
if (right == -1) {
return -1;
}
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
}
68 - I. 二叉搜尋樹的最近公共祖先
https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-zui-jin-gong-gong-zu-xian-lcof/
給定一個二叉搜尋樹, 找到該樹中兩個指定節點的最近公共祖先。
/**
* 迭代 : o(n)
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while (root != null) {
if (root.val < p.val && root.val < q.val) {
// p,q 都在 root 的右子樹中
root = root.right;
} else if (root.val > p.val && root.val > q.val) {
// p,q 都在 root 的左子樹中
root = root.left;
} else {
break;
}
}
return root;
}
68 - II. 二叉樹的最近公共祖先
https://leetcode-cn.com/problems/er-cha-shu-de-zui-jin-gong-gong-zu-xian-lcof/
給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。
/**
* 後續遍歷 : o(n)
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
return root;
}
// 遞迴遍歷左子樹,只要在左子樹中找到了p或q,則先找到誰就返回誰
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 如果在左子樹中 p和 q都找不到,則 p和 q一定都在右子樹中
if (left == null) return right;
if (right == null) return left;
return root;
}
5 棧和佇列
09. 用兩個棧實現佇列
https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
用兩個棧實現一個佇列。
class CQueue {
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if (stack2.isEmpty()) {
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.isEmpty() ? -1 : stack2.pop();
}
6 場景
10- I. 斐波那契數列
https://leetcode-cn.com/problems/fei-bo-na-qi-shu-lie-lcof/
/**
* 動規 : o(n)
*/
public int fib(int n) {
int f0 = 0, f1 = 1, tmp = 0;
for (int i = 0; i < n; i++) {
tmp = (f1 + f0) % 1000000007;
f0 = f1;
f1 = tmp;
}
return f0;
}
10- II. 青蛙跳臺階問題
https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/
一隻青蛙一次可以跳上1級臺階,也可以跳上2級臺階。求該青蛙跳上一個 n 級的臺階總共有多少種跳法。
1)解法同上,f0=1
49. 醜數
https://leetcode-cn.com/problems/chou-shu-lcof/
Medium : Marked
我們把只包含質因子 2、3 和 5 的數稱作醜數(Ugly Number)。求按從小到大的順序的第 n 個醜數。
1)動規+指標
public int nthUglyNumber(int n) {
int a = 0, b = 0, c = 0;
int[] dp = new int[n];
dp[0] = 1;
for(int i = 1; i < n; i++) {
int n2 = dp[a] * 2, n3 = dp[b] * 3, n5 = dp[c] * 5;
dp[i] = Math.min(Math.min(n2, n3), n5);
if(dp[i] == n2) a++;
if(dp[i] == n3) b++;
if(dp[i] == n5) c++;
}
return dp[n - 1];
}
61. 撲克牌中的順子
https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/
從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2~10為數字本身,A為1,J為11,Q為12,K為13,而大、小王為 0 ,可以看成任意數字。A 不能視為 14。
1)去重+最大間距
/**
* 去重+最大間距 : o(n)
*/
public boolean isStraight(int[] nums) {
// 1. 不能重複 2. max-min < 5
Set<Integer> set = new HashSet<>();
int joker = 0, max = Integer.MIN_VALUE, min = Integer.MAX_VALUE;
for (int n : nums) {
if (n == 0) {
joker++;
continue;
}
max = Math.max(max, n);
min = Math.min(min, n);
if (!set.add(n)) {
return false;
}
}
return max - min < 5;
}
2)排序(點陣圖)+模擬
/**
* 模擬 : o(n)
*/
public boolean isStraight(int[] nums) {
int[] map = new int[14];
// 排序
for (int n : nums) {
if (n == 0) {
map[n]++;
continue;
}
if (map[n] > 0) return false;
map[n] = 1;
}
// 找到最小
int i = 0, count = 0;
while (map[++i] == 0) ;
for (int j = i; j < map.length; j++) {
if (map[j] == 0 && map[0] > 0) {
map[0]--;
count++;
} else if (map[j] != 0) {
count++;
} else {
break;
}
}
// 加上剩餘大小王
count += map[0];
return count == 5;
}
62. 圓圈中最後剩下的數字
https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
0,1,n-1這n個數字排成一個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字。求出這個圓圈裡剩下的最後一個數字。
1)模擬 o(mn)
2)數學方法(約瑟夫環)
/**
* 數學迭代 : o(n)
* f(n, m) = (f(n-1, m) + m) % n
*/
public int lastRemaining(int n, int m) {
// 最後一定是下標為0的人存活,反推最初位置
int pos = 0;
for (int i = 2; i <= n; i++) {
// 每次迴圈右移
pos = (pos + m) % i;
}
return pos;
}
63. 股票的最大利潤
https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/
Medium
假設把某股票的價格按照時間先後順序儲存在陣列中,請問買賣該股票一次可能獲得的最大利潤是多少?
/**
* 動規 : o(n)
*/
public int maxProfit(int[] prices) {
// dp[i] = max( dp[i-1], price[i]-min(price[0:i]) )
if (prices == null || prices.length < 2) {
return 0;
}
int n = prices.length;
int[] dp = new int[n];
dp[0] = 0;
int min = prices[0];
for (int i = 1; i < n; i++) {
dp[i] = Math.max(dp[i - 1], prices[i] - min);
min = Math.min(min, prices[i]);
}
return dp[n - 1];
}
64. 求1+2+…+n
https://leetcode-cn.com/problems/qiu-12n-lcof/
Medium
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
1)遞迴+短路(遞迴和迴圈相互轉換)
/**
* 遞迴+短路 o(n) o(n)
*/
public int sumNums(int n) {
boolean x = n > 1 && (n += sumNums(n - 1)) > 0;
return n;
}
65. 不用加減乘除做加法
https://leetcode-cn.com/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
寫一個函式,求兩個整數之和,要求在函式體內不得使用 “+”、“-”、“*”、“/” 四則運算子號。
1)位運算
public int add(int a, int b) {
while(b != 0) { // 當進位為 0 時跳出
int c = (a & b) << 1; // c = 進位
a ^= b; // a = 非進位和
b = c; // b = 進位
}
return a;
}
66. 構建乘積陣列
https://leetcode-cn.com/problems/gou-jian-cheng-ji-shu-zu-lcof/
Medium
給定一個陣列 A[0,1,…,n-1],請構建一個陣列 B[0,1,…,n-1],其中 B 中的元素 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
1)動規+對稱遍歷
/**
* 動規 + 對稱遍歷 : o(n)
*/
public int[] constructArr(int[] a) {
if (a.length == 0) return new int[0];
int[] b = new int[a.length];
b[0] = 1;
// 計算下三角
for (int i = 1; i < a.length; i++) {
b[i] = b[i - 1] * a[i - 1];
}
int tmp = 1;
// 計算上三角
for (int i = a.length - 2; i >= 0; i--) {
tmp *= a[i + 1];
b[i] *= tmp;
}
return b;
}
相關文章
- 劍指offer導航
- Leetcode劍指offer(八)LeetCode
- 劍指offer16
- 劍指 offer20
- 劍指 offer21
- 劍指Offer題解合集
- 【劍指Offer】矩形覆蓋
- 劍指offer——跳臺階
- 六、劍指 Offer(25~29)
- 劍指offer-JavaScript版JavaScript
- 劍指offer刷題記錄
- 劍指offer-第2章
- 劍指offer第41~50題
- 劍指 offer(1) -- 陣列篇陣列
- 【劍指offer】【2】字串的空格字串
- 劍指 Offer 38. 字串的排列字串
- 《劍指 Offer》棧實現佇列佇列
- 劍指offer刷題day02
- LeetCode|劍指 Offer 49.醜數LeetCode
- 劍指offer第49題 醜數
- 劍指offer——重建二叉樹二叉樹
- 劍指Offer 表示數值的字串字串
- 劍指Offer 撲克牌順子
- 【劍指offer】2.替換空格
- 劍指offer-替換空格02
- 劍指offer解析-上(Java實現)Java
- 劍指offer解析-下(Java實現)Java
- 劍指offer 變態跳臺階
- mysql 索引十連問| 劍指 offer - mysqlMySql索引
- 秒殺劍指offer系列(41-50)
- LeetCode 劍指 Offer 05. 替換空格LeetCode
- 劍指offer之順序列印陣列陣列
- 劍指offer(四)重建二叉樹二叉樹
- 劍指offer——斐波那契數列
- 劍指offer——包含min函式的棧函式
- 劍指offer 9 變態跳臺階
- LeetCode-劍指Offer刷題記錄LeetCode
- 《劍指offer》JAVA題解,LeetCode評測JavaLeetCode