下面是的题目都会涉及双指针,除此外,还有
public class MoveZeroesLeetcode283 {
static void moveZeroes(int[] nums) {
int i = 0;
int j = 0;
while (j < nums.length) {
if (nums[j] != 0) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
i++;
}
j++;
}
}
public static void main(String[] args) {
int[] nums = {0, 1, 0, 3, 12};
moveZeroes(nums);
System.out.println(Arrays.toString(nums));
}
}
public class SumLeetcode167 {
public static void main(String[] args) {
System.out.println(Arrays.toString(twoSum(new int[]{2, 7, 11, 15}, 9)));
}
static public int[] twoSum(int[] numbers, int target) {
return twoSum(numbers, 0, numbers.length - 1, target);
}
static int[] twoSum(int[] nums, int left, int right, int target) {
int i = left;
int j = right;
while (i < j) {
if (nums[i] + nums[j] < target) {
i++;
} else if (nums[i] + nums[j] > target) {
j--;
} else {
break;
}
}
return new int[]{i + 1, j + 1};
}
}
与 Leetcode 1 的两数之和区别在于,本题的数组是升序排好的
public class SumLeetcode15 {
static List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> result = new LinkedList<>();
dfs(3, 0, nums.length - 1, 0, nums,
new LinkedList<>(), result);
return result;
}
static void dfs(int n, int i, int j, int target, int[] nums,
LinkedList<Integer> stack,
List<List<Integer>> result) {
if (n == 2) {
// 套用两数之和求解
twoSum(i, j, nums, target, stack, result);
return;
}
for (int k = i; k < j - (n - 2); k++) {
// 检查重复
if (k > i && nums[k] == nums[k - 1]) {
continue;
}
// 固定一个数字,再尝试 n-1 数字之和
stack.push(nums[k]);
dfs(n - 1, k + 1, j, target - nums[k], nums, stack, result);
stack.pop();
}
}
static int count;
static public void twoSum(int i, int j, int[] numbers, int target,
LinkedList<Integer> stack,
List<List<Integer>> result) {
count++;
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum < target) {
i++;
} else if (sum > target) {
j--;
} else { // 找到解
ArrayList<Integer> list = new ArrayList<>(stack);
list.add(numbers[i]);
list.add(numbers[j]);
result.add(list);
// 继续查找其它的解
i++;
j--;
while (i < j && numbers[i] == numbers[i - 1]) {
i++;
}
while (i < j && numbers[j] == numbers[j + 1]) {
j--;
}
}
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
int[] candidates = {-4, -1, -1, 0, 0, 1, 1, 2};
System.out.println("数据量:" + candidates.length);
System.out.println(threeSum(candidates));
System.out.println("耗费时间:" + (System.currentTimeMillis() - start));
System.out.println("递归次数:" + count);
}
}
,而本题的三数限制了递归次数仅有一次,并且每次递归终点是求两数之和时间复杂度为
,因此总时间复杂度为
public class SumLeetcode18 {
static List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> result = new LinkedList<>();
dfs(4, 0, nums.length - 1, target, nums,
new LinkedList<>(), result);
return result;
}
static void dfs(int n, int i, int j, int target, int[] nums,
LinkedList<Integer> stack,
List<List<Integer>> result) {
if (n == 2) {
// 套用两数之和求解
twoSum(i, j, nums, target, stack, result);
return;
}
for (int k = i; k < j - (n - 2); k++) { // 四数之和 i <j-2 三数之和 i <j-1
// 检查重复
if (k > i && nums[k] == nums[k - 1]) {
continue;
}
// 固定一个数字,再尝试 n-1 数字之和
stack.push(nums[k]);
dfs(n - 1, k + 1, j, target - nums[k], nums, stack, result);
stack.pop();
}
}
static int count;
static public void twoSum(int i, int j, int[] numbers, int target,
LinkedList<Integer> stack,
List<List<Integer>> result) {
count++;
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum < target) {
i++;
} else if (sum > target) {
j--;
} else { // 找到解
ArrayList<Integer> list = new ArrayList<>(stack);
list.add(numbers[i]);
list.add(numbers[j]);
result.add(list);
// 继续查找其它的解
i++;
j--;
while (i < j && numbers[i] == numbers[i - 1]) {
i++;
}
while (i < j && numbers[j] == numbers[j + 1]) {
j--;
}
}
}
}
public static void main(String[] args) {
System.out.println(fourSum(new int[]{1, 0, -1, 0, -2, 2}, 0));
// System.out.println(fourSum(new int[]{2, 2, 2, 2, 2}, 8));
// System.out.println(fourSum(new int[]{1000000000,1000000000,1000000000,1000000000}, -294967296));
}
}
public class MostWaterLeetcode11 {
static int maxArea(int[] height) {
int i = 0;
int j = height.length - 1;
int max = 0;
while (i < j) {
int min = Integer.min(height[i], height[j]);
max = Integer.max(max, (j - i) * min);
while (i < j && height[i] <= min) {
i++;
}
while (i < j && height[j] <= min) {
j--;
}
}
return max;
}
public static void main(String[] args) {
System.out.println(maxArea(new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7})); // 49
System.out.println(maxArea(new int[]{2,1})); // 1
}
}
双指针
public class ReverseStringLeetcode344 {
public static void main(String[] args) {
char[] array = "abcde".toCharArray();
reverseString(array);
System.out.println(Arrays.toString(array));
}
static void reverseString(char[] s) {
recursion(s, 0, s.length - 1);
}
public static void recursion(char[] array, int i, int j) {
if (i >= j) {
return;
}
swap(array, i, j);
recursion(array, ++i, --j);
}
public static void swap(char[] array, int i, int j) {
char c = array[i];
array[i] = array[j];
array[j] = c;
}
}
public class MonotonicStack<T extends Comparable<T>> {
private final LinkedList<T> stack = new LinkedList<>();
public void push(T t) {
while (!stack.isEmpty() && stack.peek().compareTo(t) < 0) {
stack.pop();
}
stack.push(t);
}
public void pop() {
stack.pop();
}
public T peek() {
return stack.peek();
}
@Override
public String toString() {
return stack.toString();
}
public static void main(String[] args) {
MonotonicStack<Integer> stack = new MonotonicStack<>();
for (int i : new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}) {
stack.push(i);
System.out.println(stack);
}
}
}
public class SlidingWindowMaximumLeetcode239 {
static int[] maxSlidingWindow(int[] nums, int k) {
MonotonicQueue<Integer> q = new MonotonicQueue<>();
int[] output = new int[nums.length - (k - 1)];
for (int i = 0; i < nums.length; i++) {
if (i >= k && nums[i - k] == q.peek()) {
q.poll();
}
int num = nums[i];
q.offer(num);
if (i >= k - 1) {
output[i - (k - 1)] = q.peek();
}
}
return output;
}
public static void main(String[] args) {
System.out.println(Arrays.toString(maxSlidingWindow(new int[]{1, 3, -1, -3, 5, 3, 6, 7}, 3))); //[3, 3, 5, 5, 6, 7]
System.out.println(Arrays.toString(maxSlidingWindow(new int[]{7, 2, 4}, 2))); // [7, 4]
System.out.println(Arrays.toString(maxSlidingWindow(new int[]{1, 3, 1, 2, 0, 5}, 3))); // [3, 3, 2, 5]
System.out.println(Arrays.toString(maxSlidingWindow(new int[]{-7, -8, 7, 5, 7, 1, 6, 0}, 4))); // [7, 7, 7, 7, 7]
}
}
public class MonotonicStack {
static class ValueAndIndex {
int value;
int i;
public ValueAndIndex(int value, int i) {
this.value = value;
this.i = i;
}
@Override
public String toString() {
// return "[%d]%d".formatted(index, value);
return "%d".formatted(value);
}
}
private final LinkedList<ValueAndIndex> stack = new LinkedList<>();
public void push(int value, int i, TriConsumer onPop) {
while (!stack.isEmpty() && stack.peek().value < value) {
ValueAndIndex pop = stack.pop();
ValueAndIndex peek = stack.peek();
if (peek != null) {
onPop.accept(pop.value, peek.value, peek.i);
}
}
stack.push(new ValueAndIndex(value, i));
}
@Override
public String toString() {
return stack.toString();
}
}
public class TrappingRainWaterLeetcode42 {
public static void main(String[] args) {
System.out.println(trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1})); // 6
System.out.println(trap(new int[]{4, 2, 0, 3, 2, 5})); // 9
}
record Data(int height, int i) {
}
static int trap(int[] heights) {
int sum = 0;
LinkedList<Data> stack = new LinkedList<>();
for (int i = 0; i < heights.length; i++) {
Data right = new Data(heights[i], i);
while (!stack.isEmpty() && stack.peek().height < heights[i]) {
Data pop = stack.pop();
Data left = stack.peek();
if (left != null) {
sum += (Integer.min(left.height, right.height) - pop.height) * (right.i - left.i - 1);
}
}
stack.push(right);
}
return sum;
}
}
native string matching
public class StrStrLeetcode28 {
static int strStr(String haystack, String needle) {
char[] text = haystack.toCharArray();
char[] pattern = needle.toCharArray();
int n = text.length;
int m = pattern.length;
for (int i = 0; i <= n - m; i++) {
int j;
for (j = 0; j < m; j++) {
if (pattern[j] != text[i + j]) {
break;
}
}
if (j == m) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
System.out.println(strStr("aaacaaab", "aaab"));
}
}
kmp string matching
public class StrStrLeetcode28KMP {
static int strStr(String haystack, String needle) {
char[] text = haystack.toCharArray();
char[] pattern = needle.toCharArray();
int n = text.length;
int m = pattern.length;
int[] lps = lps(pattern);
int i = 0;
int j = 0;
while ((n - i) >= (m - j)) {
if (text[i] == pattern[j]) { // 匹配成功
i++;
j++;
} else if (j != 0) { // 匹配失败
j = lsp[j - 1];
} else { // 匹配失败 j == 0
i++;
}
if (j == m) { // 找到解
return i - j;
}
}
return -1;
}
static int[] lps(char[] pattern) {
int[] lps = new int[pattern.length];
int i = 1; // 后缀
int j = 0; // 前缀 同时也是数量
while (i < pattern.length) {
if (pattern[i] == pattern[j]) {
j++;
lps[i] = j;
i++;
} else if (j != 0) {
j = lps[j - 1];
} else {
i++;
}
}
return lps;
}
public static void main(String[] args) {
System.out.println(strStr("aaaaaaab", "aaab"));
// System.out.println(Arrays.toString(prefix("aaab".toCharArray())));
System.out.println(Arrays.toString(lsp("ababaca".toCharArray())));
}
}
public class LCPLeetcode14 {
static String longestCommonPrefix(String[] strings) {
char[] first = strings[0].toCharArray();
for (int i = 0; i < first.length; i++) {
char ch = first[i];
for (int j = 1; j < strings.length; j++) {
if (i == strings[j].length() || ch != strings[j].charAt(i)) {
return new String(first, 0, i);
}
}
}
return strings[0];
}
public static void main(String[] args) {
System.out.println(longestCommonPrefix(new String[]{"flower", "flow", "flight"})); // fl
System.out.println(longestCommonPrefix(new String[]{"dog","racecar","car"})); //
System.out.println(longestCommonPrefix(new String[]{"ab","a"})); // a
System.out.println(longestCommonPrefix(new String[]{"dog","dogaa","dogbb"})); // dog
}
}
public class LongestPalindromeLeetcode5 {
public static void main(String[] args) {
System.out.println(longestPalindrome("babad")); // bab
System.out.println(longestPalindrome("cbbd")); // bb
System.out.println(longestPalindrome("a")); // a
}
record Result(int i, int length) {
static Result max(Result r1, Result r2, Result r3) {
Result m = r1;
if (r2.length > m.length) {
m = r2;
}
if (r3.length > m.length) {
m = r3;
}
return m;
}
}
static String longestPalindrome(String s) {
char[] chars = s.toCharArray();
Result max = new Result(0, 1);
for (int i = 0; i < chars.length - 1; i++) {
Result r1 = extend(chars, i, i);
Result r2 = extend(chars, i, i + 1);
max = Result.max(max, r1, r2);
}
return new String(chars, max.i, max.length);
}
private static Result extend(char[] chars, int i, int j) {
int len = chars.length;
while (i >= 0 && j < len && chars[i] == chars[j]) {
i--;
j++;
}
i++;
return new Result(i, j - i);
}
}
public class MinWindowLeetcode76_2 {
public static void main(String[] args) {
System.out.println(minWindow("ADOBECODEBANC", "ABC")); // BANC
System.out.println(minWindow("aaabbbbbcdd", "abcdd")); // abbbbbcdd
}
record Answer(int count, int i, int j) {
}
static String minWindow(String s, String t) {
char[] source = s.toCharArray();
char[] target = t.toCharArray();
int[] targetCountMap = new int[128];
int[] windowCountMap = new int[128];
for (char ch : target) {
targetCountMap[ch]++;
}
int i = 0;
int j = 0;
Answer answer = new Answer(Integer.MAX_VALUE, i, j);
int passCount = 0;
for (int count : targetCountMap) {
if (count > 0) {
passCount++;
}
}
int pass = 0;
while (j < source.length) {
char right = source[j];
int c = ++windowCountMap[right];
if (c == targetCountMap[right]) {
pass++;
}
while (pass == passCount && i <= j) {
if (j - i < answer.count) {
answer = new Answer(j - i, i, j);
}
char left = source[i];
windowCountMap[left]--;
if (windowCountMap[left] < targetCountMap[left]) {
pass--;
}
i++;
}
j++;
}
return answer.count != Integer.MAX_VALUE ? s.substring(answer.i, answer.j + 1) : "";
}
}
public class LRUCacheLeetcode146 {
static class LRUCache {
static class Node {
Node prev;
Node next;
int key;
int value;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
static class DoublyLinkedList {
private final Node head;
private final Node tail;
DoublyLinkedList() {
head = tail = new Node(-1, -1);
head.next = tail;
tail.prev = head;
}
void addFirst(Node newFirst) {
Node oldFirst = head.next;
newFirst.prev = head;
newFirst.next = oldFirst;
head.next = newFirst;
oldFirst.prev = newFirst;
}
void remove(Node node) {
Node prev = node.prev;
Node next = node.next;
prev.next = next;
next.prev = prev;
}
Node removeLast() {
Node last = tail.prev;
remove(last);
return last;
}
}
private final HashMap<Integer, Node> map = new HashMap<>();
private final DoublyLinkedList linkedList = new DoublyLinkedList();
private final int capacity;
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
Node node = map.get(key);
if (node == null) {
return -1;
}
linkedList.remove(node);
linkedList.addFirst(node);
return node.value;
}
public void put(int key, int value) {
if (map.containsKey(key)) {
Node node = map.get(key);
node.value = value;
linkedList.remove(node);
linkedList.addFirst(node);
} else {
Node node = new Node(key, value);
map.put(key, node);
linkedList.addFirst(node);
if (map.size() > capacity) {
Node last = linkedList.removeLast();
map.remove(last.key);
}
}
}
}
public static void main(String[] args) {
LRUCache cache = new LRUCache(2);
cache.put(1, 1);
cache.put(2, 2);
System.out.println(cache.get(1)); // 1
cache.put(3, 3);
System.out.println(cache.get(2)); // -1
cache.put(4, 4);
System.out.println(cache.get(1)); // -1
System.out.println(cache.get(3)); // 3
}
}
注意:
的需求
public class LFUCacheLeetcode460 {
static class LFUCache {
static class Node {
Node prev;
Node next;
int key;
int value;
int freq;
public Node() {
}
public Node(int key, int value, int freq) {
this.key = key;
this.value = value;
this.freq = freq;
}
}
static class DoublyLinkedList {
private final Node head;
private final Node tail;
int size = 0;
public DoublyLinkedList() {
head = tail = new Node();
head.next = tail;
tail.prev = head;
}
void remove(Node node) {
Node prev = node.prev;
Node next = node.next;
prev.next = next;
next.prev = prev;
node.prev = node.next = null;
size--;
}
void addFirst(Node newFirst) {
Node oldFirst = head.next;
newFirst.prev = head;
newFirst.next = oldFirst;
head.next = newFirst;
oldFirst.prev = newFirst;
size++;
}
Node removeLast() {
Node last = tail.prev;
remove(last);
return last;
}
boolean isEmpty() {
return size == 0;
}
}
private final HashMap<Integer, DoublyLinkedList> freqMap = new HashMap<>();
private final HashMap<Integer, Node> kvMap = new HashMap<>();
private final int capacity;
private int minFreq;
public LFUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
Node node = kvMap.get(key);
if (node == null) {
return -1;
}
DoublyLinkedList list = freqMap.get(node.freq);
list.remove(node);
if (node.freq == minFreq && list.isEmpty()) {
minFreq++;
}
node.freq++;
freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList()).addFirst(node);
return node.value;
}
public void put(int key, int value) {
if (kvMap.containsKey(key)) {
Node node = kvMap.get(key);
DoublyLinkedList list = freqMap.get(node.freq);
list.remove(node);
if (node.freq == minFreq && list.isEmpty()) {
minFreq++;
}
node.freq++;
node.value = value;
freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList()).addFirst(node);
} else {
if (kvMap.size() == capacity) {
Node last = freqMap.get(minFreq).removeLast();
kvMap.remove(last.key);
}
Node node = new Node(key, value, 1);
kvMap.put(key, node);
minFreq = 1;
freqMap.computeIfAbsent(node.freq, k -> new DoublyLinkedList()).addFirst(node);
}
}
}
public static void main(String[] args) {
LFUCache cache = new LFUCache(2);
cache.put(1, 1);
cache.put(2, 2);
System.out.println(cache.get(1)); // 1 freq=2
cache.put(3, 3);
System.out.println(cache.get(2)); // -1
System.out.println(cache.get(3)); // 3 freq=2
cache.put(4, 4);
System.out.println(cache.get(1)); // -1
System.out.println(cache.get(3)); // 3 freq=3
System.out.println(cache.get(4)); // 4 freq=2
}
}
公式
public class MyRandom {
private final int a;
private final int c;
private final int m;
private int seed;
public MyRandom(int a, int c, int m, int seed) {
this.a = a;
this.c = c;
this.m = m;
this.seed = seed;
}
public int nextInt() {
return seed = (a * seed + c) % m;
}
public static void main(String[] args) {
MyRandom r1 = new MyRandom(7, 0, 11, 1);
System.out.println(Arrays.toString(IntStream.generate(r1::nextInt).limit(30).toArray()));
MyRandom r2 = new MyRandom(7, 0, Integer.MAX_VALUE, 1);
System.out.println(Arrays.toString(IntStream.generate(r2::nextInt).limit(30).toArray()));
}
}
public class MyRandom2 {
private static final long a = 0x5DEECE66DL;
private static final long c = 0xBL;
private static final long m = 1L << 48;
private long seed;
public MyRandom2(long seed) {
this.seed = (seed ^ a) & (m - 1);
}
public int nextInt() {
seed = (a * seed + c) & (m - 1);
return ((int) (seed >>> 16));
}
public static void main(String[] args) {
Random r1 = new Random(1);
MyRandom2 r2 = new MyRandom2(1);
System.out.println(Arrays.toString(IntStream.generate(r1::nextInt).limit(10).toArray()));
System.out.println(Arrays.toString(IntStream.generate(r2::nextInt).limit(10).toArray()));
}
}
设计一个方法调用若干次,每次返回 1~max 的数字,从 1 开始,返回数字的比例减半,例如 max = 4,让大概
/*
第一轮有 500 个(level 1) >= 0.5 退出循环,剩下 500 个(level 2)
第二轮有 250 个(level 2) >= 0.5 退出循环,剩下 125 个(level 3)
第三轮有 63 个(level 3) >= 0.5 退出循环,剩下 62 个(level 4) 由于第二个条件退出循环
*/
static int randomLevel(int max) {
int level = 1;
while (Math.random() < 0.5 && level < max) {
level++;
}
return level;
}
public class SkipListLeetcode1206 {
public static void main(String[] args) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < 1000; i++) {
int level = Skiplist.randomLevel();
map.compute(level, (k, v) -> v == null ? 1 : v + 1);
}
System.out.println(map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> String.format("%d%%", e.getValue() * 100 / 1000))));
}
static class Skiplist {
static final int MAX = 4;
static int randomLevel() {
int level = 1;
while (Math.random() < 0.5 && level < MAX) {
level++;
}
/*
第一轮有 500 个(level 1) >= 0.5 退出循环,剩下 500 个(level 2)
第二轮有 250 个(level 2) >= 0.5 退出循环,剩下 125 个(level 3)
第三轮有 63 个(level 3) >= 0.5 退出循环,剩下 62 个(level 4) 由于第二个条件退出循环
*/
return level;
}
private final Node head = new Node(-1);
static class Node {
int val;
Node[] next;
public Node(int val) {
this.val = val;
this.next = new Node[MAX];
}
}
private Node[] find(int val) {
Node[] path = new Node[MAX];
Node curr = head;
for (int lvl = MAX - 1; lvl >= 0; lvl--) {
while (curr.next[lvl] != null && curr.next[lvl].val < val) {
curr = curr.next[lvl];
}
path[lvl] = curr;
}
return path;
}
public boolean search(int val) {
Node[] path = find(val);
Node node = path[0].next[0];
return node != null && node.val == val;
}
public void add(int val) {
Node[] path = find(val);
int lv = randomLevel();
Node node = new Node(val);
for (int i = 0; i < lv; i++) {
node.next[i] = path[i].next[i];
path[i].next[i] = node;
}
}
public boolean erase(int val) {
Node[] path = find(val);
Node node = path[0].next[0];
if (node == null || node.val != val) {
return false;
}
for (int i = 0; i < MAX; i++) {
if (path[i].next[i] != node) {
break;
}
path[i].next[i] = node.next[i];
}
return true;
}
}
}
下楼梯规则
节点的【高度】
解法1
static class MinStack {
LinkedList<Integer> stack = new LinkedList<>();
LinkedList<Integer> min = new LinkedList<>();
public MinStack() {
min.push(Integer.MAX_VALUE);
}
public void push(int val) {
stack.push(val);
min.push(Math.min(val, min.peek()));
}
public void pop() {
if (stack.isEmpty()) {
return;
}
stack.pop();
min.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return min.peek();
}
}
解法2
static class MinStack2 {
record Data(int val, int min) {
}
final LinkedList<Data> stack = new LinkedList<>();
public void push(int val) {
if (stack.isEmpty()) {
stack.push(new Data(val, val));
} else {
Data peek = stack.peek();
stack.push(new Data(val, Math.min(val, peek.min)));
}
}
public void pop() {
stack.pop();
}
public int top() {
return stack.peek().val;
}
public int getMin() {
return stack.peek().min;
}
}
public class TinyURLLeetcode535 {
public static void main(String[] args) {
/*CodecSequence codec = new CodecSequence();
String encoded = codec.encode("https://leetcode.cn/problems/1");
System.out.println(encoded);
encoded = codec.encode("https://leetcode.cn/problems/2");
System.out.println(encoded);*/
// for (int i = 0; i <= 62; i++) {
// System.out.println(i + "\t" + CodecSequence.toBase62(i));
// }
System.out.println(CodecSequence.toBase62(237849728));
}
/*
要让【长】【短】网址一一对应
1. 用【随机数】作为短网址标识
2. 用【hash码】作为短网址标识
3. 用【递增数】作为短网址标识
1) 多线程下可以使用吗?
2) 分布式下可以使用吗?
3) 4e9iAk 是怎么生成的?
a-z 0-9 A-Z 62进制的数字
0 1 2 3 4 5 6 7 8 9 a b c d e f
十进制 => 十六进制
31 1f
31 % 16 = 15
31 / 16 = 1
1 % 16 = 1
1 / 16 = 0
长网址: https://leetcode.cn/problems/encode-and-decode-tinyurl/description/
对应的短网址: http://tinyurl.com/4e9iAk
*/
static class CodecSequence {
private static final char[] toBase62 = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
public static String toBase62(int number) {
if (number == 0) {
return String.valueOf(toBase62[0]);
}
StringBuilder sb = new StringBuilder();
while (number > 0) {
int r = number % 62;
sb.append(toBase62[r]);
number = number / 62;
}
return sb.toString();
}
private final Map<String, String> longToShort = new HashMap<>();
private final Map<String, String> shortToLong = new HashMap<>();
private static final String SHORT_PREFIX = "http://tinyurl.com/";
private static int id = 1;
public String encode(String longUrl) {
String shortUrl = longToShort.get(longUrl);
if (shortUrl != null) {
return shortUrl;
}
// 生成短网址
shortUrl = SHORT_PREFIX + id;
longToShort.put(longUrl, shortUrl);
shortToLong.put(shortUrl, longUrl);
id++;
return shortUrl;
}
public String decode(String shortUrl) {
return shortToLong.get(shortUrl);
}
}
static class CodecHashCode {
private final Map<String, String> longToShort = new HashMap<>();
private final Map<String, String> shortToLong = new HashMap<>();
private static final String SHORT_PREFIX = "http://tinyurl.com/";
public String encode(String longUrl) {
String shortUrl = longToShort.get(longUrl);
if (shortUrl != null) {
return shortUrl;
}
// 生成短网址
int id = longUrl.hashCode(); // int
while (true) {
shortUrl = SHORT_PREFIX + id;
if (!shortToLong.containsKey(shortUrl)) {
longToShort.put(longUrl, shortUrl);
shortToLong.put(shortUrl, longUrl);
break;
}
id++;
}
return shortUrl;
}
public String decode(String shortUrl) {
return shortToLong.get(shortUrl);
}
}
static class CodecRandom {
private final Map<String, String> longToShort = new HashMap<>();
private final Map<String, String> shortToLong = new HashMap<>();
private static final String SHORT_PREFIX = "http://tinyurl.com/";
public String encode(String longUrl) {
String shortUrl = longToShort.get(longUrl);
if (shortUrl != null) {
return shortUrl;
}
// 生成短网址
while (true) {
int id = ThreadLocalRandom.current().nextInt();// 1
shortUrl = SHORT_PREFIX + id;
if (!shortToLong.containsKey(shortUrl)) {
longToShort.put(longUrl, shortUrl);
shortToLong.put(shortUrl, longUrl);
break;
}
}
return shortUrl;
}
public String decode(String shortUrl) {
return shortToLong.get(shortUrl);
}
}
}
线性合并
static class Twitter2 {
static int time;
static class Tweet {
int id;
int time;
Tweet next;
public Tweet(int id, int time, Tweet next) {
this.id = id;
this.time = time;
this.next = next;
}
public int id() {
return id;
}
public int time() {
return time;
}
}
static class User {
Integer id;
public User(Integer id) {
this.id = id;
}
Set<Integer> followees = new HashSet<>();
Tweet head = new Tweet(-1, -1, null);
}
private final Map<Integer, User> userMap = new HashMap<Integer, User>();
public void postTweet(int userId, int tweetId) {
User user = userMap.computeIfAbsent(userId, User::new);
user.head.next = new Tweet(tweetId, time++, user.head.next);
}
public List<Integer> getNewsFeed(int userId) {
User user = userMap.get(userId);
if (user == null) {
return List.of();
}
Tweet p1 = user.head.next;
for (Integer id : user.followees) {
p1 = merge(p1, userMap.get(id).head.next);
}
LinkedList<Integer> result = new LinkedList<>();
int count = 0;
while (p1 != null && count < 10) {
result.addLast(p1.id);
p1 = p1.next;
count++;
}
return result;
}
private Tweet merge(Tweet p1, Tweet p2) {
Tweet head = new Tweet(-1, -1, null);
Tweet p0 = head;
int count = 0;
while (p1 != null && p2 != null && count < 10) {
if (p1.time > p2.time) {
p0.next = new Tweet(p1.id, p1.time, null);
p0 = p0.next;
p1 = p1.next;
} else {
p0.next = new Tweet(p2.id, p2.time, null);
p0 = p0.next;
p2 = p2.next;
}
count++;
}
while (p1 != null && count < 10) {
p0.next = new Tweet(p1.id, p1.time, null);
p0 = p0.next;
p1 = p1.next;
count++;
}
while (p2 != null && count < 10) {
p0.next = new Tweet(p2.id, p2.time, null);
p0 = p0.next;
p2 = p2.next;
count++;
}
return head.next;
}
public void follow(int userId, int followeeId) {
User user = userMap.computeIfAbsent(userId, User::new);
User followee = userMap.computeIfAbsent(followeeId, User::new);
user.followees.add(followeeId);
}
public void unfollow(int userId, int followeeId) {
User user = userMap.get(userId);
if (user != null) {
user.followees.remove(followeeId);
}
}
}
优先级队列合并
public class TwitterLeetcode355 {
static class Twitter {
static class Tweet {
int id;
int time;
Tweet next;
public Tweet(int id, int time, Tweet next) {
this.id = id;
this.time = time;
this.next = next;
}
public int getId() {
return id;
}
public int getTime() {
return time;
}
}
static class User {
int id;
public User(int id) {
this.id = id;
}
Set<Integer> followees = new HashSet<>();
Tweet head = new Tweet(-1, -1, null);
}
private final Map<Integer, User> userMap = new HashMap<>();
private static int time;
// 发布文章
public void postTweet(int userId, int tweetId) {
User user = userMap.computeIfAbsent(userId, User::new);
user.head.next = new Tweet(tweetId, time++, user.head.next);
}
// 新增关注
public void follow(int userId, int followeeId) {
User user = userMap.computeIfAbsent(userId, User::new);
User followee = userMap.computeIfAbsent(followeeId, User::new);
user.followees.add(followee.id);
}
// 取消关注
public void unfollow(int userId, int followeeId) {
User user = userMap.get(userId);
if (user != null) {
user.followees.remove(followeeId);
}
}
// 获取最新10篇文章(包括自己和关注用户)
public List<Integer> getNewsFeed(int userId) {
User user = userMap.get(userId);
if (user == null) {
return List.of();
}
PriorityQueue<Tweet> queue
= new PriorityQueue<>(Comparator.comparingInt(Tweet::getTime).reversed());
if(user.head.next != null) {
queue.offer(user.head.next);
}
for (Integer id : user.followees) {
User followee = userMap.get(id);
if(followee.head.next != null) {
queue.offer(followee.head.next);
}
}
List<Integer> res = new ArrayList<>();
int count = 0;
while (!queue.isEmpty() && count < 10) {
Tweet max = queue.poll();
res.add(max.id);
if (max.next != null) {
queue.offer(max.next);
}
count++;
}
return res;
}
}
}
public class SharesI {
static int maxProfit(int[] prices) {
int i = 0;
int j = 1;
int max = 0;
while (j < prices.length) {
if (prices[j] - prices[i] > 0) {
max = Math.max(max, prices[j] - prices[i]);
j++;
} else {
i = j;
j++;
}
}
return max;
}
public static void main(String[] args) {
System.out.println(maxProfit(new int[]{9, 3, 12, 1, 2, 3, 11}));
}
}
public class SharesIILeetcode122 {
static int maxProfit(int[] prices) {
int i = 0;
int j = 1;
int max = 0;
while (j < prices.length) {
if (prices[j] - prices[i] > 0) { // 有利润
max += prices[j] - prices[i];
}
i = j;
j++;
}
return max;
}
public static void main(String[] args) {
System.out.println(maxProfit(new int[]{9, 3, 12, 1, 2, 3})); // 11
System.out.println(maxProfit(new int[]{7, 1, 5, 3, 6, 4})); // 7
}
}
public class SharesLeetcode714 {
/*
0 1 2 3 4 5
1 3 2 8 4 9
买 -1 等-1 √ 等-1 √ 等-1 √ -1 等1 √
买-3 买-2 买-8 买1 √ 买-4
卖 0 等0 √ 等0 √ 等0 等5 √ 等5
卖0 卖-1 卖5 √ 卖1 卖8 √
*/
static int maxProfit(int[] prices, int fee) {
int b1 = -prices[0];
int s1 = 0;
for (int i = 1; i < prices.length; i++) {
int s0 = Math.max(s1, b1 + prices[i] - fee);
int b0 = Math.max(b1, s1 - prices[i]);
s1 = s0;
b1 = b0;
}
return s1;
}
public static void main(String[] args) {
System.out.println(maxProfit(new int[]{1, 3, 2, 8, 4, 9}, 2)); // 8
System.out.println(maxProfit(new int[]{1, 3, 7, 2, 18, 3}, 3)); // 16
//
System.out.println(maxProfit(new int[]{1, 3, 7, 5, 10, 3}, 3)); // 6
System.out.println(maxProfit(new int[]{1, 3, 7, 5, 10, 11, 3}, 3)); // 7
System.out.println(maxProfit(new int[]{2,1,4,4,2,3,2,5,1,2}, 1)); // 4
}
}
降维
static int maxProfit(int[] prices, int fee) {
// _buy _sell 代表上一次 buy sell 代表这一次
int _buy = -prices[0];
int _sell = 0;
for (int i = 1; i < prices.length; i++) {
int buy = Math.max(_buy, _sell - prices[i]);
int sell = Math.max(_sell, _buy + prices[i] - fee);
_buy = buy;
_sell = sell;
}
return _sell;
}
结构优化(非性能)
static int maxProfit(int[] prices, int fee) {
int buy = Integer.MIN_VALUE;
int sell = 0;
for (int price : prices) {
buy = Math.max(buy, sell - price);
/*
若 max 是 上次 buy,那么显然用这次 buy 是一样的
若 max 是 上次 sell - prices[i], 则
Math.max(sell, sell - prices[i] + prices[i] - fee);
==>
Math.max(sell, sell - fee);
显然后面的式子不可能比上次 sell 更大,此时新的 sell 只由上次 sell 决定,与 上次 buy 无关
*/
sell = Math.max(sell, buy + price - fee);
}
return sell;
}
public class SharesLeetcode309 {
/*
0 1 2 3 4
1 2 3 0 2
买 -1 -2 -3 1√ 0
等 -1√ -1√ -1 1√
卖 0 1√ 2√ -1 3√
等 0 1 2√ 2
*/
static int maxProfit(int[] prices) {
if (prices.length == 1) {
return 0;
}
int[] buy = new int[prices.length];
int[] sell = new int[prices.length];
buy[0] = -prices[0];
sell[0] = 0;
buy[1] = Math.max(-prices[0], -prices[1]);
sell[1] = Math.max(sell[0], buy[0] + prices[1]);
for (int i = 2; i < prices.length; i++) {
buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]);
sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
}
return sell[prices.length - 1];
}
public static void main(String[] args) {
System.out.println(maxProfit(new int[]{1, 2, 3, 0, 2})); // 3
}
}
降维
static int maxProfit(int[] prices) {
if (prices.length == 1) {
return 0;
}
int __sell = 0;
int _sell = 0;
int _buy = -prices[0];
for (int i = 1; i < prices.length; i++) {
int buy = Math.max(_buy, __sell - prices[i]);
int sell = Math.max(_sell, prices[i] + _buy);
_buy = buy;
__sell = _sell;
_sell = sell;
}
return _sell;
}
public class SharesIIILeetcode123 {
static int maxProfit(int[] prices) {
int buy1 = Integer.MIN_VALUE;
int sell1 = 0;
int buy2 = Integer.MIN_VALUE;
int sell2 = 0;
for (int price : prices) {
buy1 = Math.max(buy1, -price);
sell1 = Math.max(sell1, buy1 + price);
buy2 = Math.max(buy2, sell1 - price);
sell2 = Math.max(sell2, buy2 + price);
}
return sell2;
}
public static void main(String[] args) {
System.out.println(maxProfit(new int[]{3, 3, 5, 0, 0, 3, 1, 4})); // 6
}
}
public class SharesLeetcode188 {
static int maxProfit(int[] prices) {
int i = 0;
int j = 1;
int sum = 0;
while (j < prices.length) {
if (prices[j] - prices[i] > 0) { // 有利润
sum += prices[j] - prices[i];
}
i++;
j++;
}
return sum;
}
static int maxProfit(int k, int[] prices) {
if (k > prices.length / 2) {
return maxProfit(prices);
}
int[] buy = new int[k];
int[] sell = new int[k];
Arrays.fill(buy, Integer.MIN_VALUE);
for (int price : prices) {
buy[0] = Math.max(buy[0], -price);
sell[0] = Math.max(sell[0], buy[0] + price);
for (int j = 1; j < k; j++) {
buy[j] = Math.max(buy[j], sell[j - 1] - price);
sell[j] = Math.max(sell[j], buy[j] + price);
}
}
return sell[k - 1];
}
public static void main(String[] args) {
// System.out.println(maxProfit(2, new int[]{3, 2, 6, 5, 0, 3})); // 7
System.out.println(maxProfit(2, new int[]{3, 3, 5, 0, 0, 3, 1, 4})); // 6
}
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有