方法论
看数据范围,判断考察的算法
剑指offer
13. 找出数组中重复的数字
题目详情
https://www.acwing.com/problem/content/14/
分析
利用题目条件,一个萝卜一个坑的思想(魔方盲拧编码思想)
class Solution {public int duplicateInArray(int[] nums) {int n = nums.length;// 题目要求for (int num : nums) {if (num < 0 || num > n - 1) return -1;}for (int i = 0; i < n; ++i) {// 一个萝卜一个坑while (nums[i] != i) {// 自己坑错了,但对的坑里有对的萝卜了,说明这俩萝卜相等if (nums[i] == nums[nums[i]]) return nums[i];// 将i位置的萝卜放到正确的坑swap(nums, i, nums[i]);}}return -1;}private void swap(int[] nums, int a, int b) {int temp = nums[a];nums[a] = nums[b];nums[b] = temp;}}
14. 不修改数组找出重复的数字(二分查找)
题目详情
https://www.acwing.com/problem/content/15/
分析
本题涉及的二分查找算是一种变形,不是查找一个数字,查到了就return,而是二分查找取值区间,所以需要实现[left, mid], [mid+1, right]这样的全覆盖,而且当left==right的时候就退出循环,所以while (left < right)。就本体来讲,是找到一个区间,里面取值范围跨度<区间内数字个数
class Solution {public int duplicateInArray(int[] nums) {// 抽屉原理,至少有一个重复数字// 用递归思想来做,把取值区间分成两部分,至少有一个区间内有重复数字int left = 1, right = nums.length - 1;while (left < right) { // 注意!int mid = left + (right - left) / 2;int sum = 0; // 有多少数字在取值[left, mid]区间内for (int num: nums) {if (num >= left && num <= mid) sum++;}if (sum > mid - left + 1) right = mid; // 注意!在取值区间[left, mid]里继续搜索else left = mid + 1; // [mid+1, right]里继续搜索}return left; // right == left}}
二分查找模板
int bsearch_1(int l, int r){while (l < r){int mid = l + r >> 1;if (check(mid)) r = mid;else l = mid + 1;}return l;}
15. 二维数组中的查找(略)
16. 替换空格(略)
17. 从尾到头打印链表
/*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/class Solution {public int[] printListReversingly(ListNode head) {Deque<Integer> stack = new ArrayDeque<>();ListNode temp = head;while (temp != null) {stack.addFirst(temp.val);temp = temp.next;}int[] result = new int[stack.size()];int i = 0;while (!stack.isEmpty()) result[i++] = stack.removeFirst();return result;}}
Java的Stack类已经不再使用,而是使用Deque实现。
Deque使用小结:
将元素添加到队尾或队首:addLast()/offerLast()/addFirst()/offerFirst()
从队首/队尾获取元素并删除:removeFirst()/pollFirst()/removeLast()/pollLast()
从队首/队尾获取元素但不删除:getFirst()/peekFirst()/getLast()/peekLast()

