LRU 缓存
java
class LRUCache {
private int capacity;
private Map<Integer, Integer> map = new LinkedHashMap<>();
public LRUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
Integer value = map.remove(key);
if(value != null){ //key已存在,更新value
map.put(key, value);
return value;
}
return -1;
}
public void put(int key, int value) {
Integer val = map.remove(key);
if(val != null){//key存在
map.put(key, value);
return;
}
//如果不存在,当前key压根就没被发现,所以容量还是capacity
if(map.size() == capacity){
int index = map.keySet().iterator().next();//找到迭代器的第一个元素
map.remove(index);
}
map.put(key, value);
}
}
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
LFU 缓存
java
class LFUCache {
private final int capacity;
private final Map<Integer, Integer> keyToFreq = new HashMap<>();
private final Map<Integer, Map<Integer, Integer>> freqToMap = new HashMap<>();
private int minFreq;
public LFUCache(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
return move(key, null);
}
public void put(int key, int value) {
if(move(key, value) != -1){
return;
}
if(keyToFreq.size() == capacity){
Map<Integer, Integer> map = freqToMap.get(minFreq);
Integer oldestKey = map.keySet().iterator().next();
map.remove(oldestKey);
keyToFreq.remove(oldestKey);
}
keyToFreq.put(key, 1);
freqToMap.computeIfAbsent(1, k -> new LinkedHashMap<>()).put(key, value);
minFreq = 1;
}
//把key从第freq摞书中抽出来,放到第freq+1摞书的最上面
//返回key对应的value
public int move(Integer key, Integer value){
Integer freq = keyToFreq.getOrDefault(key, null);
if(freq == null){
return - 1;
}
Map<Integer, Integer> map = freqToMap.get(freq);
Integer v = map.remove(key);
if(value == null){
value = v;
}
if(map.size() == 0 && minFreq == freq){
minFreq++;
}
keyToFreq.merge(key, 1, Integer::sum);
freqToMap.computeIfAbsent(freq + 1, k -> new LinkedHashMap<>()).put(key, value);
return value;
}
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/
带 TTL 的 LRU
java
package mianshi;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Cache {
private final int capacity;
private final int ttl;
private final LinkedHashMap<Integer, Integer> cache;
private final Map<Integer, Integer> expireTimes;
public Cache(int capacity, int ttl){
this.capacity = capacity;
this.ttl = ttl;
this.cache = new LinkedHashMap<>();
this.expireTimes = new HashMap<>();
startAutoCleaner();
}
public int get(int key){
Integer value = cache.remove(key);
if(value == null){
return -1;
}
//有这个元素
cache.put(key, value);
expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl); //更新元素的过期时间
return value;
}
public void put(int key, int value){
Integer v = cache.remove(key);
if(v != null){//已存在的元素
cache.put(key, value);
expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl);
return;
}
//不存在的元素,要put新元素
if(cache.size() == capacity){
Integer index = cache.keySet().iterator().next();
cache.remove(index);
expireTimes.remove(index);
}
cache.put(key, value);
expireTimes.put(key, (int)(System.currentTimeMillis() / 1000) + ttl);
}
public void startAutoCleaner(){
ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor();
//固定频率的任务
cleaner.scheduleAtFixedRate(
() -> {
int currentTime = (int)(System.currentTimeMillis() / 1000);
expireTimes.keySet().removeIf(
key ->{
if(currentTime > expireTimes.get(key)){
cache.remove(key);
expireTimes.remove(key);
return true;
}
return false;
}
);
},
0,
1,
TimeUnit.SECONDS
);
}
}
最长递增子序列
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n + 1]; //至少是1
Arrays.fill(dp, 1);
//dp[i]表示以i为结尾的最长递增子序列长度
//对于每个选定的字符都需要验证在他前面的字符都是小于此字符的,只有如此才能接上上一个子序列
int ans = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= i; j++){
if(nums[i - 1] > nums[j - 1]){
dp[i] = Math.max(dp[j] + 1, dp[i]);//要么当前字符大于前面字符可以接上,要么从现在开始
}
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
合并两个升序链表
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
cur.next = new ListNode(list1.val);
list1 = list1.next;
}else{
cur.next = new ListNode(list2.val);
list2 = list2.next;
}
cur = cur.next;
}
//单独处理两个
cur.next = (list1 != null) ? list1 : list2;
return dummy.next;
}
}
数组中第 k 个最大元素
215. 数组中的第K个最大元素 - 力扣(LeetCode)
java
class Solution {
public int findKthLargest(int[] nums, int k) {
ArrayList<Integer> list = new ArrayList<>();
for(int i : nums){
list.add(i);
}
return maxSerach(list, k);
}
public int maxSerach(ArrayList<Integer> list, int k){
int n = list.size();
Random r = new Random();
int pivot = list.get(r.nextInt(n));
ArrayList<Integer> small = new ArrayList<>();
ArrayList<Integer> equal = new ArrayList<>();
ArrayList<Integer> big = new ArrayList<>();
for(int num : list){
if(num > pivot) big.add(num);
else if(num < pivot) small.add(num);
else equal.add(num);
}
if(k <= big.size()){
return maxSerach(big, k);
}
if(n - k < small.size()){
return maxSerach(small, k - n + small.size());
}
return pivot;
}
}
打家劫舍
java
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n == 1) return nums[0];
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = nums[0];
//当前偷窃的最大金额是要么是这个屋的现金,要么是前两个屋+现在的金额
for(int i = 2; i <= n; i++){
dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]);
}
return dp[n];
}
}
最长有效括号
java
class Solution {
public int longestValidParentheses(String s) {
int n = s.length();
char[] chars = s.toCharArray();
int maxLen = 0;
Deque<Integer> st = new ArrayDeque<>();
st.push(-1);
for(int i = 0; i < n; i++){
if(chars[i] == '('){
st.push(i);
}else{
st.pop();
if(st.isEmpty()){
st.push(i);
}else{
maxLen = Math.max(maxLen, i - st.peek());
}
}
}
return maxLen;
}
}
合并区间
java
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (p, q) -> (p[0] - q[0]));
List<int[]> list = new ArrayList<>();
for(int[] num : intervals){
int m = list.size();
if(m > 0 && list.get(m - 1)[1] >= num[0]){
list.get(m - 1)[1] = Math.max(list.get(m - 1)[1], num[1]);
}else{
list.add(num);
}
}
return list.toArray(new int[list.size()][]);
}
}
分隔链表
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode partition(ListNode head, int x) {
ListNode bigDummy = new ListNode(0);
ListNode smallDummy = new ListNode(0);
ListNode big = bigDummy;
ListNode small = smallDummy;
while(head != null){
if(head.val < x){
small.next = head;
small = small.next;
}else{
big.next = head;
big = big.next;
}
head = head.next;
}
big.next = null;//重要
small.next = bigDummy.next;
return smallDummy.next;
}
}
寻找峰值
java
class Solution {
public int findPeakElement(int[] nums) {
int l = 0;
int r = nums.length - 1;
while(l < r){
int mid = (l + r) / 2;
if(nums[mid] < nums[mid + 1]) l = mid + 1;
else r = mid;
}
return l;
}
}
字符串相加
java
class Solution {
public String addStrings(String num1, String num2) {
StringBuilder sb = new StringBuilder("");
int n = num1.length() - 1;
int m = num2.length() - 1;
int carry = 0;
while(n >= 0 || m >= 0){
int a = n >= 0 ? num1.charAt(n) - '0' : 0;
int b = m >= 0 ? num2.charAt(m) - '0' : 0;
int res = (a + b + carry) % 10;
carry = (a + b + carry) / 10;
sb.append(res);
n--;
m--;
}
if(carry == 1) sb.append(1);
return sb.reverse().toString();
}
}
反转字符串中的单词
java
class Solution {
public String reverseWords(String s) {
StringBuilder sb = new StringBuilder("");
List<String> list = new ArrayList<>();
StringBuilder ss = new StringBuilder("");
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) != ' '){
ss.append(s.charAt(i));
}else{
if(ss.length() != 0 && ss != null){
list.add(ss.toString());
ss.setLength(0);
}
}
}
if(ss.length() != 0 && ss != null) list.add(ss.toString());
for(int i = list.size() - 1; i >= 0; i--){
if(i != 0){
sb.append(list.get(i));
sb.append(" ");
}else{
sb.append(list.get(i));
}
}
return sb.toString();
}
}
java
class Solution {
public String reverseWords(String s) {
s = s.trim();
int i = s.length() - 1, j = i;
StringBuilder sb = new StringBuilder();
while(i >= 0){
while(i >= 0 && s.charAt(i) != ' ') i--;//找到第一个空格
sb.append(s.substring(i + 1, j + 1) + ' ');
while(i >= 0 && s.charAt(i) == ' ') i--;
j = i; //j是下一个单次的末尾坐标
}
return sb.toString().trim();
}
}
最小覆盖子串
java
class Solution {
public String minWindow(String s, String t) {
int[] cntS = new int[128];
int[] cntT = new int[128];
for(char a : t.toCharArray()){
cntT[a]++;
}
int left = 0;
int ansLeft = - 1;//ansleft+ansright=s.length()
int ansRight = s.length() - 1;
char[] chars = s.toCharArray();
for(int right = 0; right < s.length(); right++){
cntS[chars[right]]++;//进入窗口
while(converted(cntS, cntT)){ //如果当前字串满足题意,计算当前字串的长度
if(right - left < ansRight - ansLeft){
ansLeft = left;
ansRight = right;
}
//尝试剔除左侧窗口字符
cntS[chars[left]]--;
left++;
}
}
return ansLeft == - 1 ? "" : s.substring(ansLeft, ansRight + 1);
}
public boolean converted(int[] cntS, int[] cntT){
for(int i = 'a'; i <= 'z'; i++){
if(cntS[i] < cntT[i]){
return false;
}
}
for(int i = 'A'; i <= 'Z'; i++){
if(cntS[i] < cntT[i]){
return false;
}
}
return true;
}
}
反转链表
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while(cur != null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
回文链表
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
}
ListNode back = reverseList(slow);
ListNode cur = head;
while(cur != null && back != null){
if(back.val != cur.val){
return false;
}
cur = cur.next;
back = back.next;
}
return true;
}
public ListNode reverseList(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(cur != null){
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
在排序数组中查找一个元素的第一个和最后一个位置
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
java
class Solution {
public int[] searchRange(int[] nums, int target) {
int l = 0;
int r = nums.length - 1;
while(l <= r){
int mid = l + r >>> 1;
if(nums[mid] >= target){
r = mid - 1;
}else{
l = mid + 1;
}
}
if(l == nums.length || nums[l] != target) return new int[]{-1, -1};
int begin = l;
while(l < nums.length && nums[l] == target)l++;
return new int[]{begin, l - 1};
}
}
合并两个有序数组
java
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1;
int j = n - 1;
int index = n + m - 1;
while(index >= 0 && i >= 0 && j >= 0){
if(nums1[i] >= nums2[j]){
nums1[index] = nums1[i];
i--;
}else{
nums1[index] = nums2[j];
j--;
}
index--;
}
while(j >= 0){
nums1[index] = nums2[j];
index--;
j--;
}
}
}
滑动窗口最大值
java
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque<Integer> dq = new ArrayDeque<>();
int n = nums.length;
int[] ans = new int[n - k + 1];
for(int right = 0; right < n; right++){
while(!dq.isEmpty() && nums[dq.getLast()] <= nums[right]){
dq.removeLast();
}
dq.addLast(right);
int left = right - k + 1;
if(left > dq.getFirst()){
dq.removeFirst();
}
if(left >= 0){
ans[left] = nums[dq.getFirst()];
}
}
return ans;
}
}
编辑距离
java
class Solution {
public int minDistance(String word1, String word2) {
int n = word1.length();
int m = word2.length();
int[][] dp = new int[n + 1][m + 1];//dp[i][j]表示从i转换到j所需要的最少操作数
//预处理边界为,某个单词长度为0
for(int i = 1; i <= n; i++) dp[i][0] = dp[i - 1][0] + 1;
for(int j = 1; j <= m; j++) dp[0][j] = dp[0][j - 1] + 1;
int ans = 0;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(word1.charAt(i - 1) == word2.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1];
else dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
}
}
return dp[n][m];
}
}
无重复字符的最长子串
java
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s == null || s.length() == 0) return 0;
int n = s.length();
int[] cnt = new int[128];
int len = 0;
int left = 0;
char[] chars = s.toCharArray();
for(int right = 0; right < n; right++){
cnt[chars[right]]++;
while(cnt[chars[right]] > 1){
cnt[chars[left]]--;
left++;
}
len = Math.max(right - left + 1, len);
}
return len;
}
}
有效的括号
java
class Solution {
public boolean isValid(String s) {
if(s.length() % 2 != 0) return false;
Map<Character, Character> mp = new HashMap<>();
mp.put('(', ')');
mp.put('[', ']');
mp.put('{', '}');
Deque<Character> q = new ArrayDeque<>();
char[] chars = s.toCharArray();
for(int i = 0; i < s.length(); i++){
if(mp.containsKey(chars[i])){
q.addLast(chars[i]); //如果是左括号,直接插入
}else{ //遇到右括号,弹出栈顶元素,对比是否匹配
if(mp.get(q.getLast()) != chars[i]){
return false;
}
q.removeLast();
}
}
if(!q.isEmpty()) return false;
return true;
}
}
用 Rand7()实现 Rand10()
470. 用 Rand7() 实现 Rand10() - 力扣(LeetCode)
使用 rand7(),首先尝试扩大范围,因为 1-7 无法生成 1-10 的内容,所以我们给 rand7() *7,现在的范围是不连续的 7 个数,7,14,21,28,35,42,49,需要加 rand7()补上这些区间的空缺,但是现在有个问题就是 1-6 没法得到,所以给 (rand7() - 1) * 7,缩小一下范围,0, 7,14,21,28,35,42,此时+rand7(),把大于 40 的全部拒绝,每个数字的概率都是 4/49。
java
/**
* The rand7() API is already defined in the parent class SolBase.
* public int rand7();
* @return a random integer in the range 1 to 7
*/
class Solution extends SolBase {
public int rand10() {
while(true){
int a = rand7();
int b = rand7();
int num = (a - 1) * 7 + b;
if(num <= 40) return (num - 1) % 10 + 1;
}
}
}
java
/**
* The rand7() API is already defined in the parent class SolBase.
* public int rand7();
* @return a random integer in the range 1 to 7
*/
class Solution extends SolBase {
public int rand10() {
while(true){
int a = rand7();
int b = rand7();
int num = (a - 1) * 7 + b;
if(num <= 40) return (num - 1) % 10 + 1;
else{
// 1-9
int newNum = (num - 41) * 7 + rand7();
if(newNum <= 60) return (newNum - 1) % 10 + 1;
}
}
}
}
寻找重复数
链表的结构是:节点+next 指针
在这个题目中,节点可以理解为是当前下标,next 指针指向的是 numsi,基于此可以把数组转化为链表,这个题目就变成了寻找链表成环的入口。
慢指针的路程:a+x
快指针的路程:a+x+n*环长
快指针速度是慢指针的两倍:相遇时
2(a+x) = a + x + n*环长
a = n* 环长-x
a = 环长-x
所以起点到入口的距离=相遇点到入口的距离
所以再搞一个指针,两个指针同时走,下次相遇就是重复点
java
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0;
int fast = 0;
while(true){
slow = nums[slow];
fast = nums[nums[fast]];
if(fast == slow) break; //相遇点
}
slow = 0;
while(slow != fast){
slow = nums[slow];
fast = nums[fast];
}
return slow;
}
}
排序数组(手撕快排)
java
class Solution {
private static final Random ran = new Random();
public int[] sortArray(int[] nums) {
quickSort(nums, 0, nums.length - 1);
return nums;
}
public void quickSort(int[] nums, int l, int r){
boolean ordered = true;
for(int i = l; i < r; i++){
if(nums[i] > nums[i + 1]){
ordered = false;
break;
}
}
if(ordered) return; //已经有序了
int mid = partition(nums, l, r); //分区找到pivot
quickSort(nums, l, mid - 1);
quickSort(nums, mid + 1, r);
}
public int partition(int[] nums, int l, int r){
int i = l + ran.nextInt(r - l + 1);
int pivot = nums[i];
swap(nums, i, l);
i = l + 1;
int j = r;
while(true){
while(i <= j && nums[i] < pivot) i++;//找到大于pivot的
while(i <= j && nums[j] > pivot) j--;//找到小于pivot的
if(i >= j) break;
swap(nums, i, j);
i++;
j--;
}
swap(nums, l, j);
return j;
}
public void swap(int[] nums, int l, int r){
int tmp = nums[l];
nums[l] = nums[r];
nums[r] = tmp;
}
}
二分查找
java
class Solution {
public int search(int[] nums, int target) {
int l = 0;
int r = nums.length - 1;
while(l <= r){
int mid = (l + r) / 2;
if(nums[mid] < target) l = mid + 1;
else if(nums[mid] > target) r = mid - 1;
else return mid;
}
return -1;
}
}
最大子数组和
java
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length + 1];
int maxSum = nums[0];
for(int i = 1; i <= nums.length; i++){
dp[i] = Math.max(dp[i - 1] + nums[i - 1], nums[i - 1]);
maxSum = Math.max(dp[i], maxSum);
}
return maxSum;
}
}
寻找两个正序数组的中位数
4. 寻找两个正序数组的中位数 - 力扣(LeetCode)
java
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
int[] nums = new int[n + m];
int index = 0;
int i = 0;
int j = 0;
while(i < n && j < m){
if(nums1[i] <= nums2[j]){
nums[index] = nums1[i];
i++;
}else{
nums[index] = nums2[j];
j++;
}
index++;
}
while(i < n){
nums[index] = nums1[i];
i++;
index++;
}
while(j < m){
nums[index] = nums2[j];
j++;
index++;
}
return (n + m) % 2 != 0 ? 1.0 * nums[(n+m) / 2] : 1.0 *(nums[(n + m) / 2] + nums[(n + m) / 2 - 1]) / 2;
}
}
颜色分类
先把全部颜色当成 2,再把应该是 1 的覆盖回来,把应该是 0 的覆盖掉。
java
class Solution {
public void sortColors(int[] nums) {
int p0 = 0; //放0的位置
int p1 = 0; //放1的位置
for(int i = 0; i < nums.length; i++){
int x = nums[i];
nums[i] = 2;
if(x <= 1) nums[p1++] = 1;
if(x == 0) nums[p0++] = 0;
}
}
}
通配符匹配
java
class Solution {
public boolean isMatch(String s, String p) {
int n = s.length();
int m = p.length();
boolean[][] dp = new boolean[n + 1][m + 1]; //表示前i位和j位字符匹配
dp[0][0] = true;
//如果输入s是空串
for(int j = 1; j <= m; j++){
if(p.charAt(j - 1) == '*'){
dp[0][j] = dp[0][j - 1];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(p.charAt(j - 1) == '?' || s.charAt(i - 1) == p.charAt(j - 1)){ //第j位是?表示可以随便匹配s
dp[i][j] = dp[i - 1][j - 1];
}else if(p.charAt(j - 1) == '*'){
//不包含* 相当于包含*,但是跟i的前一位比,因为*本身就可以替代
dp[i][j] = dp[i][j - 1] || dp[i - 1][j];
}
}
}
return dp[n][m];
}
}
删除排序链表的重复元素
83. 删除排序链表中的重复元素 - 力扣(LeetCode)
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = head;
ListNode cur = head;
while(cur != null && cur.next != null){
if(cur.val == cur.next.val){
cur.next = cur.next.next;
}else cur = cur.next;
}
return dummy;
}
}
删除链表中的重复元素 II
82. 删除排序链表中的重复元素 II - 力扣(LeetCode)
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode cur = dummy;
while(cur.next != null && cur.next.next != null){
if(cur.next.val == cur.next.next.val){
int x = cur.next.val;
while(cur.next != null && cur.next.val == x){
cur.next = cur.next.next;
}
}else{
cur = cur.next;
}
}
return dummy.next;
}
}
最小覆盖子串
java
class Solution {
public String minWindow(String s, String t) {
int[] cntS = new int[128];
int[] cntT = new int[128];
char[] cs = s.toCharArray();
char[] ct = t.toCharArray();
for(char c : ct) cntT[c]++;
int left = 0;
int ansLeft = -1;
int ansRight = -1;
int minLen = Integer.MAX_VALUE;
for(int right = 0; right < cs.length; right++){
cntS[cs[right]]++;
while(converted(cntS, cntT)){
if(right - left + 1 < minLen){
minLen = right - left + 1;
ansLeft = left;
ansRight = right;
}
cntS[cs[left]]--;
left++;
}
}
return ansLeft == -1 ? "" : s.substring(ansLeft, ansRight + 1);
}
public boolean converted(int[] cntS, int[] cntT){
for(int i = 'a'; i <= 'z'; i++){
if(cntS[i] < cntT[i]) return false;
}
for(int i = 'A'; i <= 'Z'; i++){
if(cntS[i] < cntT[i]) return false;
}
return true;
}
}
数组中重复的数据(重要)
java
class Solution {
public List<Integer> findDuplicates(int[] nums) {
//因为所有整数都在[1,n]内,所以每个整数都可以当作数组下标,把访问过的整数标为负数,下次如果再次访问到负数,说明当前位置被重复访问,也就是数组中数据重复
List<Integer> ans = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
int x = Math.abs(nums[i]);//获取整数值当作下标
int index = x -1;
if(nums[index] < 0) ans.add(x); //查看下标位置是否为负数
else nums[index] = -nums[index];
}
return ans;
}
}
最接近的三数之和
java
class Solution {
public int threeSumClosest(int[] nums, int target) {
int ans = 0;
int diff = Integer.MAX_VALUE;
for(int i = 0; i < nums.length; i++){
for(int j = i + 1; j < nums.length; j++){
for(int k = j + 1; k < nums.length; k++){
int sum = nums[i] + nums[j] + nums[k];
if(Math.abs(sum - target) < diff){
diff = Math.abs(sum - target);
ans = sum;
}
}
}
}
return ans;
}
}
java
class Solution {
public int threeSumClosest(int[] nums, int target) {
int n = nums.length;
int diff = Integer.MAX_VALUE;
int ans = 0;
Arrays.sort(nums);
for(int i = 0; i < n - 2; i++){
if(i > 0 && nums[i] == nums[i - 1]) continue;
int l = i + 1;
int r = n - 1;
while(l < r){
int sum = nums[i] + nums[l] + nums[r];
if(sum == target) return target;
if(Math.abs(sum - target) < diff){
diff = Math.abs(sum - target);
ans = sum;
}
if(sum > target) r--;
else l++;
}
}
return ans;
}
}
三数之和
java
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
Arrays.sort(nums);
for(int i = 0; i < n - 2; i++){
if(i > 0 && nums[i] == nums[i - 1]) continue;
if(nums[i] + nums[i + 1] + nums[i + 2] > 0) break;
if(nums[i] + nums[n - 2] + nums[n - 1] < 0) continue;
int l = i + 1;
int r = n - 1;
while(l < r){
if(nums[i] + nums[l] + nums[r] > 0){
r--;
}else if(nums[i] + nums[l] + nums[r] < 0){
l++;
}else{
ans.add(List.of(nums[i], nums[l], nums[r]));
for(l++; l < r && nums[l] == nums[l - 1]; l++);
for(r--; l < r && nums[r] == nums[r + 1]; r--);
}
}
}
return ans;
}
}
和为 s 的连续正数序列
文件编号就是自然数序列 1, 2, 3, 4, 5, 6,...,找出和为 target 的组合。
java
class Solution {
public int[][] fileCombination(int target) {
List<int[]> ans = new ArrayList<>();
int l = 1;
int preSum = 0;
for(int r = 1; r <= target - 1; r++){
preSum += r;
while(preSum > target){
preSum -= l;
l++;
}
if(preSum == target){
int[] list = new int[r - l + 1];
for(int i = l; i <= r; i++){
list[i - l] = i;
}
ans.add(list);
}
}
return ans.toArray(new int[ans.size()][]);
}
}
两两交换链表中的节点
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
while(cur.next != null && cur.next.next != null){
ListNode node1 = cur.next;
ListNode node2 = cur.next.next;
cur.next = node2; //node2现在是头节点
node1.next = node2.next; //让 node1 指向后面的节点,防止断链
node2.next = node1;//让 node2 指向 node1,完成反转
cur = node1;
}
return dummy.next;
}
}
ip 地址转化为 10 进制整数
192.168.1.1
由于每一位都是 0-255,所以用 8 位二进制表示,相当于 192 左移 24 位,168 左移 16 位,1 左移 8 位,1 不移。
java
import java.util.*;
public class Althoriom {
public static void main(String[] args) {
String ip = "10.0.3.193";
System.out.println(ipToInt(ip));
}
public static long ipToInt(String ip){
long ans = 0;
String[] part = ip.split("\\."); //反斜杠 \\用来转义
for(int i = 0; i < 4; i++){
long res = Long.parseLong(part[i]);
ans |= (res << (24 - 8 * i));
}
return ans;
}
}
复原 IP 地址
java
class Solution {
private List<String> ans = new ArrayList<>();
public List<String> restoreIpAddresses(String s) {
backtrack(s, 0, new ArrayList<>());
return ans;
}
public void backtrack(String s, int start, List<String> tmp){
if(tmp.size() == 4){
if(start == s.length()){
ans.add(String.join(".", tmp));
return;
}
}
for(int len = 1; len <= 3; len++){
if(start + len > s.length()) break;
String str = s.substring(start, start + len);
if(isValid(str)){
tmp.add(str);
backtrack(s, start + len, tmp);
tmp.remove(tmp.size() - 1);
}
}
}
public boolean isValid(String str){
if(str.length() > 1 && str.charAt(0) == '0') return false;
int num = 0;
for(int i = 0; i < str.length(); i++){
num = num * 10 + str.charAt(i) - '0';
}
return num >= 0 && num <= 255;
}
}
前 K 个高频单词
java
class Solution {
public List<String> topKFrequent(String[] words, int k) {
Map<String,Integer> map = new HashMap<>();
for(int i = 0; i < words.length; i++){
map.put(words[i], map.getOrDefault(words[i], 0) + 1);
}
PriorityQueue<String> pq = new PriorityQueue<>(
(p, q) -> {
int countP = map.get(p);
int countQ = map.get(q);
if(countP != countQ){
return countQ - countP;
}
return p.compareTo(q);
}
); //大根堆
for (String s : map.keySet()) {
pq.offer(s);
}
List<String> ans = new ArrayList<>();
for(int i = 0; i < k; i++){
ans.add(pq.poll());
}
return ans;
}
}