LRU
import java.util.HashMap;
class LRUCache {
public static class Node {
Node next, pre;
int key, val;
Node(int k, int v) {
//少了这两行会报空指针
next = this;
pre = this;
key = k;
val = v;
}
}
HashMap<Integer, Node> map = new HashMap<>();
int capacity;
Node head;
public LRUCache(int capacity) {
this.capacity = capacity;
head = new Node(0, 0);
}
public int get(int key) {
/**
* 1、判断map包不包含key,
* 2.1 不包含return -1
* 2.2包含的话refresh放到链表前面,返回node.val
*/
if (!map.containsKey(key)) return -1;
Node node = map.get(key);
refresh(node);
return node.val;
}
public void put(int key, int value) {
/**
* 1、先判断包不包含key
* 2.1 包含则更新node.val,然后refresh到前面
* 2.2 不包含则map插入,然后refresh,最后判断有没有超过capacity,超过则del
*/
if (map.containsKey(key)) {
Node node = map.get(key);
node.val = value;
refresh(node);
} else {
Node node = new Node(key, value);
map.put(key, node);
refresh(node);
if (map.size() > capacity) {
del();
}
}
}
private void refresh(Node node) {
/**
* 双向链表就是 把当前节点的next 指向下一个结点
* 下一个节点的pre指向当前节点
*/
// 删除这个node
node.next.pre = node.pre;
node.pre.next = node.next;
//把它加在前面
node.pre = head;
head.next.pre = node;
node.next = head.next;
head.next = node;
}
private void del() {
Node node = head.pre;
node.next.pre = node.pre;
node.pre.next = node.next;
map.remove(node.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));
cache.put(3, 3);
System.out.println(cache.get(2));
cache.put(4, 4);
System.out.println(cache.get(1));
System.out.println(cache.get(3));
System.out.println(cache.get(4));
}
}
快排
找到基准值,把小于基准值的放在他前面,大于的放到他后面,同时,序列被划分成两个子序列,再分别对两个子序列进行快速排序,直到子序列的长度为1,则完成排序。
import java.util.*;
public class QuickSort {
public int[] sortArray(int[] nums){
quickSort(nums, 0, nums.length -1);
return nums;
}
public void quickSort(int[] nums, int left, int right) {
if(nums == null)
return;
if(left >= right)
return;
int i = left;
int j = right;
int temp = nums[i];
while(i < j){
while(i < j && temp <= nums[j]){
j--;
}
nums[i] = nums[j];
while (i < j && temp >= nums[i]) {
i++;
}
nums[j] = nums[i];
nums[i] = temp;
}
quickSort(nums,left,i-1);
quickSort(nums,i+1,right);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] num = sc.nextLine().split(" ");
int[] nums = new int[num.length];
for(int i = 0; i < num.length;i++){
nums[i] = Integer.valueOf(num[i]);
}
QuickSort test = new QuickSort();
int[] res = test.sortArray(nums);
for(int i: res){
System.out.print(i+" ");
}
}
}
数组
1299. 将每个元素替换为右侧最大元素
题目
思路:
逆序解决,而且不能用多余的空间,
arr[i] = max(arr[i+1],res[i+1])
import java.util.Map;
import java.util.Scanner;
public class Solution {
public int[] replaceElements(int[] arr){
int cur_max = arr[arr.length-1];
arr[arr.length-1] = -1;
for(int i = arr.length-2;i >=0;i--){
int tmp = arr[i];
arr[i] = Math.max(cur_max,arr[i+1]);
cur_max = tmp;
}
return arr;
}
public static void main(String[] args){
Solution test = new Solution();
Scanner sc = new Scanner(System.in);
String[] nums = null;
nums = sc.nextLine().split(" ");
int[] arr = new int[nums.length];
for(int i = 0;i < nums.length;i++){
arr[i] = Integer.valueOf(nums[i]);
}
int[] res = test.replaceElements(arr);
for(int i:res){
System.out.print(i+" ");
}
}
}
42.接雨水
题目
思路:
记录该位置左边的最大值和右边的最大值,然后该位置接水量就是Math.min(right[i],left[i]) - height[i]
import java.util.Scanner;
public class Solution {
public int trap(int[] height){
if (height.length < 3){
return 0;
}
int[] right = new int[height.length];
int[] left = new int[height.length];
left[0] = height[0];
right[height.length - 1] = height[height.length - 1];
for(int i = 1;i<height.length;i++){
left[i] = Math.max(height[i],left[i-1]);
}
for(int i = height.length - 2 ;i >= 0;i--){
right[i] = Math.max(height[i],right[i+1]);
}
int res = 0;
for(int i = 0;i < height.length;i++){
res += Math.min(right[i],left[i]) - height[i];
}
return res;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String[] nums = null;
nums = sc.nextLine().split(" ");
int[] height = new int[nums.length];
for(int i=0;i<nums.length;i++){
height[i] = Integer.valueOf(nums[i]);
}
Solution test = new Solution();
System.out.println(test.trap(height));
}
}
单调栈
84.柱状图中最大的矩形
当找到比栈顶元素小的时候,就把栈顶元素弹出,计算area。
package Array;
import util.ArrayInputUtil;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 84.柱状图最大的矩形
* [0,9]出错
*/
public class LargestRectangleArea {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 0) {
return 0;
}
if (len == 1) {
return heights[0];
}
int[] newHeights = new int[len + 2];
Deque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < len; i++) {
newHeights[i + 1] = heights[i];
}
heights = newHeights;
stack.add(0);
int area = 0;
for (int i = 1; i < heights.length; i++) {
while (heights[i] < heights[stack.peekLast()]) {
int height = heights[stack.removeLast()];
int width = i - stack.peekLast() - 1;
area = Math.max(area,height * width);
}
stack.add(i);
}
return area;
}
public static void main(String[] args) {
// int[] height = ArrayInputUtil.arrayInput();
int[] height = {2,1,5,6,2,3};
LargestRectangleArea test = new LargestRectangleArea();
System.out.println(test.largestRectangleArea(height));
}
}
739.每日温度
题目
思路:
简历一个从栈顶到栈底递增的栈,当当前元素大于栈顶,即可出栈,记录过了多少天,否则出栈。
package monotonousStack;
import java.util.ArrayDeque;
import java.util.Deque;
public class DailyTemperatures {
public int[] dailyTemperatures(int[] T) {
int len = T.length;
int[] res = new int[len];
if (len == 0 || len == 1) {
return res;
}
Deque<Integer> stack = new ArrayDeque<>();
stack.add(0);
for(int i = 1;i < T.length;i++){
while(!stack.isEmpty() && T[i] > T[stack.peekLast()]){
int j = stack.removeLast();
res[j] = i - j;
}
stack.add(i);
}
return res;
}
public static void main(String[] args) {
int[] T = {73, 74, 75, 71, 69, 72, 76, 73};
DailyTemperatures test = new DailyTemperatures();
int[] res = test.dailyTemperatures(T);
for (int i = 0; i < res.length; i++) {
System.out.print(res[i] + " ");
}
}
}
503.下一个更大元素II
题目
思路:
建立一个单调递增的栈,如果当前元素大于就出栈,并记录,注意是循环数组,所以需要第二个for循环处理一次。
package monotonousStack;
import java.util.*;
/**
* 503.下一个最大元素
* [5,4,3,2,1]出错
*/
public class NextGreaterElements {
public int[] nextGreaterElements(int[] nums) {
int[] res = new int[nums.length];
if (nums.length == 0) {
return res;
}
if (nums.length == 1) {
res[0] = -1;
return res;
}
Arrays.fill(res, -1);
Deque<Integer> stack = new ArrayDeque<>();
stack.add(0);
for (int i = 1; i < nums.length; i++) {
while (!stack.isEmpty() && nums[i] > nums[stack.peekLast()]) {
int j = stack.removeLast();
res[j] = nums[i];
}
stack.add(i);
}
for (int i = 0; i < nums.length - 1; i++) {
while (!stack.isEmpty() && nums[i] > nums[stack.peekLast()]) {
int j = stack.removeLast();
res[j] = nums[i];
}
stack.add(i);
}
return res;
}
public static void main(String[] args) {
int[] nums = {5,4,3,2,1};
NextGreaterElements test = new NextGreaterElements();
int[] res = test.nextGreaterElements(nums);
for (int i = 0; i < res.length; i++) {
System.out.print(res[i] + " ");
}
}
}
双指针
三数之和
题目
思路:
排序后,用双指针
注意:
1、排除重复答案的
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
2、判断tmp==0后不能直接left++ right–
while(left < right && nums[left] == nums[left+1]){
left += 1;
}
while(left < right && nums[right] == nums[right - 1]){
right -= 1;
}
import java.lang.reflect.Array;
import java.util.*;
public class Solution {
public List<List<Integer>> threeSum(int[] nums){
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(nums.length < 3){
return res;
}
Arrays.sort(nums);
for(int i = 0;i<nums.length-2;i++){
// 处理 答案重复
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i + 1;
int right = nums.length - 1;
while(left < right){
int tmp = nums[i] + nums[left] + nums[right];
if (tmp == 0){
List<Integer> cur = new ArrayList<>();
cur.add(nums[i]);
cur.add(nums[left]);
cur.add(nums[right]);
res.add(cur);
while(left < right && nums[left] == nums[left+1]){
left += 1;
}
while(left < right && nums[right] == nums[right - 1]){
right -= 1;
}
left += 1;
right -=1;
}
else if(tmp > 0){
right -= 1;
}
else{
left += 1;
}
}
}
return res;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String[] arr = null;
arr = sc.nextLine().split(" ");
int[] nums = new int[arr.length];
for(int i = 0;i < arr.length;i++){
nums[i] = Integer.valueOf(arr[i]);
}
Solution test = new Solution();
System.out.println(test.threeSum(nums));
}
}
滑动窗口
3. 无重复字符的最长子串
题目
思路:
极端例子 “abcbfa”
用一个map记录s[i]及其索引位置,map(s[i],index)
用start和end来记录窗口,当出现s[i]在map时,则将start更新到index + 1,然后更新index,当出现s[i]在map时,但是index<start说明窗口不包括了,即忽略掉;
java实现
import java.util.*;
public class LengthOfLongestSubString {
public int lengthOfLongestSubString(String s) {
if (s.length() == 0) {
return 0;
}
Map<Character, Integer> map = new HashMap<>();
int res = 0;
int start = 0;
int end = 0;
for(int i = 0;i < s.length();i++) {
char c = s.charAt(i);
if(!map.containsKey(c) || map.get(c) < start){
map.put(c,i);
end = i;
res = Math.max(res, end - start + 1);
}
else{
start = map.get(c) + 1;
map.put(c,i);
end = i;
res = Math.max(res, end - start + 1);
}
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
LengthOfLongestSubString test = new LengthOfLongestSubString();
System.out.println(test.lengthOfLongestSubString(s));
}
}
python实现
# -*- coding: utf-8 -*-
class Solution(object):
def lengthOfLongestSubstring(self, s):
if not s:
return 0
s_dict = {}
start = 0
res = 0
for i in range(len(s)):
if s[i] not in s_dict.keys() or s_dict[s[i]] < start:
s_dict[s[i]] = i
end = i
res = max(res, end - start + 1)
else:
start = s_dict[s[i]] + 1
s_dict[s[i]] = i
end = i
res = max(res, end - start + 1)
return res
if __name__ == "__main__":
s = input()
test = Solution()
print(test.lengthOfLongestSubstring(s))
1004.最大连续1的个数III
题目
最大窗口随着满足条件而增大,假如不满足条件就保持原来大小往右滑
参考:https://www.bilibili.com/video/BV1Sb411v7qp?from=search&seid=7404090548336897110
# -*- coding: utf-8 -*-
class Solution(object):
def problem(self,A,K):
l = 0
for r in range(len(A)):
if A[r] == 0:
K -= 1
if K < 0:
if A[l] == 0:
K += 1
l += 1
return r - l + 1
if __name__ == '__main__':
K = int(input())
A = list(map(int,input().split()))
test = Solution()
print(test.problem(A,K))
424.替换后的最长重复子串
题目
思路:
记录窗口内字符的数量,并记录这些字符中出现的最大次数
假如当前窗口- 最大次数大于k,说明这个窗口是替换完都不行的,因此左指针后移,并吧窗口内的字符次数-1
import java.util.*;
public class CharacterReplacement {
public int characterReplacement(String s, int k) {
char[] chars = new char[26];
int historyMaxlen = 0;
int res = 0;
int l = 0;
for (int r = 0; r < s.length(); r++) {
char c = s.charAt(r);
chars[c - 'A']++;
historyMaxlen = Math.max(historyMaxlen, chars[c - 'A']);
if (r - l + 1 - historyMaxlen > k) {
char lc = s.charAt(l);
chars[lc - 'A']--;
l++;
}
res = Math.max(res, r - l + 1);
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int k = sc.nextInt();
CharacterReplacement test = new CharacterReplacement();
System.out.println(test.characterReplacement(s, k));
}
}
# -*- coding: utf-8 -*-
class Solution(object):
def problem(self,s,k):
l = 0
res = 0
char = [0] * 26
## 用historyMax替换掉max(char)
historyMax = 0
for r in range(len(s)):
char[ord(s[r]) - ord('A')] += 1
historyMax = max(historyMax,char[ord(s[r]) - ord('A')])
if r - l + 1 - historyMax > k:
char[ord(s[l]) - ord('A')] -= 1
l += 1
res = max(res, r - l + 1)
return res
if __name__ == '__main__':
s = input()
k = int(input())
test = Solution()
print(test.problem(s,k))
动态规划
120.三角形最小路径和
题目
思路:
自底向上:
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
# -*- coding: utf-8 -*-
class Solution(object):
def problem(self, triangle):
n = len(triangle)
for i in range(n-2,-1,-1):
for j in range(i+1):
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
return triangle[0][0]
if __name__ == '__main__':
nums = []
n = int(input())
for i in range(n):
l = list(map(int, input().split()))
nums.append(l)
test = Solution()
print(test.problem(nums))
最大子序列和
题目
思路:
假如当前的curMax < 0,curMax要重新计,curMax = nums[i],否则相加起来跟res比较
import java.util.*;
public class MaxSubArray {
public int maxSubArray(int[] nums) {
int curMax = nums[0];
int res = nums[0];
for (int i = 1; i < nums.length; i++) {
if (curMax < 0) {
curMax = nums[i];
} else {
curMax += nums[i];
}
if (curMax > res) {
res = curMax;
}
}
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String[] stringArray = sc.nextLine().split(" ");
int[] nums = new int[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
nums[i] = Integer.valueOf(stringArray[i]);
}
MaxSubArray test = new MaxSubArray();
System.out.println(test.maxSubArray(nums));
}
}
121.买卖股票I
题目
思路:
前后做差,求最大的子序列和。
package dp;
public class MaxProfit {
public int maxProfit(int[] prices) {
int len = prices.length;
if (len <= 1) {
return 0;
}
int[] nums = new int[len - 1];
for(int i = 1; i<len;i++){
nums[i-1] = prices[i] - prices[i-1];
}
int res = maxSubArray(nums);
return res > 0 ? res: 0;
}
public int maxSubArray(int[] nums) {
int curSum = nums[0];
int maxSum = nums[0];
for(int i = 1;i<nums.length;i++){
if(curSum > 0){
curSum += nums[i];
}
else{
curSum = nums[i];
}
if(curSum > maxSum){
maxSum = curSum;
}
}
return maxSum;
}
public static void main(String[] args) {
int[] prices = {7, 1, 5, 3, 6, 4};
MaxProfit test = new MaxProfit();
System.out.println(test.maxProfit(prices));
}
}
另外一个思路:
记录当前最小的数值,做差更新maxprofit
class Solution:
def maxProfit(self, prices: List[int]) -> int:
min_val = sys.maxsize
max_profit = 0
for i in prices:
if i < min_val:
min_val = i
else:
if max_profit < i - min_val:
max_profit = i - min_val
return max_profit
122.买卖股票II
题目
思路:
直接前后想减,把差值大于零相加起来。
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
res = 0
for i in range(1,len(prices)):
if prices[i] - prices[i-1] > 0:
res += prices[i] - prices[i-1]
return res
221.最大正方形
题目
思路:
注意边界判断,
matrix[i][j] == '1’的时候,才进行dp[i][j] = min(dp[i-1][j-1],[i-1][j],[i][j-1]) + 1
import java.util.*;
public class MaximalSquare {
public int maximalSquare(char[][] matrix) {
int maxLen = 0;
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return maxLen;
}
int row = matrix.length;
int col = matrix[0].length;
int[][] dp = new int[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (matrix[i][j] == '1') {
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i - 1][j - 1]), dp[i][j - 1]) + 1;
}
maxLen = Math.max(dp[i][j], maxLen);
}
}
}
return maxLen * maxLen;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int row = sc.nextInt();
int col = sc.nextInt();
char[][] maxtrix = new char[row][col];
for (int r = 0; r < row; r++) {
for (int c = 0; c < col; c++) {
//输入字符
maxtrix[r][c] = sc.next().charAt(0);
}
}
MaximalSquare test = new MaximalSquare();
System.out.println(test.maximalSquare(maxtrix));
}
}
516.最长回文子序列
题目
思路:
用dp[i][j] 表示i和j最长的回文子序列
i从0向右遍历,j从i-1向左遍历
如果i和j的字符相等,那么相当于dp[i][j] = dp[i - 1][j + 1] + 2;
如果不等,则:dp[i][j] = Math.max(dp[i - 1][j], dp[i][j + 1]);
package dp;
import java.util.Scanner;
/**
* 516,最长回文子序列
*/
public class LongestPalindromeSubseq {
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];
for (int i = 0; i < n; i++) {
dp[i][i] = 1;
for (int j = i - 1; j >= 0; j--) {
if (s.charAt(i) == s.charAt(j)) {
dp[i][j] = dp[i - 1][j + 1] + 2;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j + 1]);
}
}
}
return dp[n - 1][0];
}
public static void main(String[] args) {
LongestPalindromeSubseq test = new LongestPalindromeSubseq();
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(test.longestPalindromeSubseq(s));
}
}
链表
206.反转链表
public class Solution {
public ListNode reverseList(ListNode head){
ListNode pre = null;
ListNode cur = head;
while(head != null){
cur = head;
head = head.next; //注意把提前这一行放这里
cur.next = pre;
pre = cur;
}
return cur;
}
public static void main(String[] args) {
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(5);
Solution test = new Solution();
ListNode res = test.reverseList(head);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
反转链表2
题目
思路
第一步:找到待反转节点的前一个节点。记录为beforInverNode,并记录开始反转的节点startInverNode
第二步:反转m到n这部分。
第三步:将反转的起点的next指向反转的后面一部分。
第四部:将startInverNode的next指向后面不需要反转的部分
注意反转完后链表的状态:
所以需要:
beforeInverseNode.next = pre;
startInverseNode.next = node;
import java.util.List;
public class Solution {
public ListNode reverseBetween(ListNode head,int m,int n){
int i = 0;
ListNode pHead = new ListNode(0);
pHead.next = head;
head = pHead;
ListNode start = null;
ListNode end = null;
ListNode pEnd = null;
while (head != null) {
if (i == m - 1) {
pEnd = head;
start = head.next;
}
if (n == i) {
end = head;
ListNode tmp = head.next;
end.next = null;
HashMap<String, ListNode> map = reverseList(start);
ListNode reverseHead = map.get("head");
ListNode reverseTail = map.get("tail");
pEnd.next = reverseHead;
reverseTail.next = tmp;
head = reverseTail;
}
head = head.next;
i++;
}
return pHead.next;
}
public static void main(String[] args) {
int m = 2, n = 6;
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
head.next.next.next.next.next = new ListNode(6);
head.next.next.next.next.next.next = new ListNode(7);
Solution test = new Solution();
ListNode res = test.reverseBetween(head,m,n);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
k个一组翻转链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode pHead = new ListNode(0);
pHead.next = head;
ListNode pEnd = pHead;
ListNode start = head;
int i = 0;
while (head != null) {
i++;
if (i == k) {
ListNode nextstart = head.next;
ListNode end = head;
end.next = null;
HashMap<String,ListNode> map = reverseList(start);
pEnd.next = map.get("head");
head = map.get("tail");
head.next = nextstart;
pEnd = head;
start = nextstart;
i = 0;
}
head = head.next;
}
return pHead.next;
}
public HashMap<String, ListNode> reverseList(ListNode head) {
HashMap<String, ListNode> map = new HashMap<>();
map.put("tail", head);
ListNode pre = null;
ListNode cur = head;
while (head != null) {
cur = head;
head = head.next;
cur.next = pre;
pre = cur;
}
map.put("head", cur);
return map;
}
}
21.合并两个有序链表
题目
递归
public class Solution {
public ListNode mergeTwoLists(ListNode l1,ListNode l2){
if(l1 == null){
return l2;
}
else if(l2 == null){
return l1;
}
else if(l1.val < l2.val){
l1.next = mergeTwoLists(l1.next,l2);
return l1;
}
else{
l2.next = mergeTwoLists(l1,l2.next);
return l2;
}
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
l1.next = new ListNode(2);
l1.next.next = new ListNode(4);
ListNode l2 = new ListNode(1);
l2.next = new ListNode(3);
l2.next.next = new ListNode(4);
Solution test = new Solution();
ListNode res = test.mergeTwoLists(l1,l2);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
23.合并k个排序链表
题目
思路:
分治,两两合并
public class Solution {
public ListNode mergeKlists(ListNode[] lists){
int interval = 1;
int len = lists.length;
while(len > interval){
for(int i = 0;i < len - interval; i += interval * 2){
lists[i] = merge2lists(lists[i], lists[i + interval]);
}
interval *= 2;
}
return len > 0 ? lists[0]:null;
}
public ListNode merge2lists(ListNode l1,ListNode l2){
if(l1 == null){
return l2;
}
else if(l2 == null){
return l1;
}
else if(l1.val < l2.val){
l1.next = merge2lists(l1.next,l2);
return l1;
}
else{
l2.next = merge2lists(l1,l2.next);
return l2;
}
}
public static void main(String[] args) {
// ListNode l1 = new ListNode(1);
// l1.next = new ListNode(4);
// l1.next.next = new ListNode(5);
//
// ListNode l2 = new ListNode(1);
// l2.next = new ListNode(3);
// l2.next.next = new ListNode(4);
//
// ListNode l3 = new ListNode(2);
// l3.next = new ListNode(6);
// ListNode[] lists = {l1,l2,l3};
ListNode[] lists = {};
Solution test = new Solution();
ListNode res = test.mergeKlists(lists);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
141.环形链表
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while(head!=null){
if(set.contains(head)){
return true;
}
else{
set.add(head);
}
head = head.next;
}
return false;
}
}
142.环形链表ii
题目
思路:
快慢指针
import java.util.HashSet;
import java.util.Set;
public class Solution {
public ListNode detectCycle(ListNode head){
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next!= null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
fast = head;
while (fast != slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
return null;
}
public static void main(String[] args) {
ListNode head = new ListNode(3);
ListNode node = new ListNode(2);
head.next = node;
head.next.next = new ListNode(0);
head.next.next.next = new ListNode(-4);
head.next.next.next.next = node;
Solution test = new Solution();
ListNode res = test.detectCycle(head);
System.out.println(res.val);
}
}
83.删除排序链表中的重复元素
public class Solution {
public ListNode deleteDuplicates(ListNode head){
if(head == null){
return null;
}
ListNode cur = head;
while(head.next != null){
if(head.val != head.next.val){
head = head.next;
}
else{
//这一步很关键
head.next = head.next.next;
}
}
return cur;
}
public static void main(String[] args) {
ListNode head = new ListNode(1);
head.next = new ListNode(1);
head.next.next = new ListNode(2);
head.next.next.next = new ListNode(3);
head.next.next.next.next = new ListNode(3);
Solution test = new Solution();
ListNode res = test.deleteDuplicates(head);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
倒数第k个节点
题目
思路:快指针先走k步
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode fast = head;
int i = 0;
while(fast != null && i < k){
fast = fast.next;
i++;
}
ListNode slow = head;
if(i == k){
while(fast != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
return null;
}
}
19.删除链表的倒数第N个节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
int i = 0;
while(fast != null && i < n){
fast = fast.next;
i++;
}
//防止[1] n = 1和[1,2] n = 2
if(fast == null){
head = head.next;
return head;
}
if(i == n){
ListNode pre = new ListNode(0);
pre.next = head;
ListNode slow = head;
while(fast != null){
fast = fast.next;
head = slow;
slow = slow.next;
}
head.next = slow.next;
return pre.next;
}
return null;
}
public static void main(String[] args) {
int n = 2;
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
// head.next.next.next = new ListNode(4);
// head.next.next.next.next = new ListNode(5);
// head.next.next.next.next.next = new ListNode(6);
// head.next.next.next.next.next.next = new ListNode(7);
Solution test = new Solution();
ListNode res = test.removeNthFromEnd(head,n);
while(res != null){
System.out.print(res.val + " ");
res = res.next;
}
}
}
二叉树
144.二叉树的前序遍历
import java.util.ArrayList;
import java.util.List;
public class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root){
if(root != null){
res.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
}
return res;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.right = new TreeNode(2);
root.right.left = new TreeNode(3);
Solution test = new Solution();
System.out.println(test.preorderTraversal(root));
}
}
102.二叉树的层序遍历
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class TreeLevelOrder {
/**
* 102.二叉树的层序遍历
*/
public List<List<Integer>> levelOrder(TreeNode root){
List<List<Integer>> res = new ArrayList<>();
if(root == null){
return res;
}
List<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(queue.size() > 0){
int len = queue.size();
List<Integer> cur = new ArrayList<>();
for(int i = 0;i < len;i++){
TreeNode curNode = queue.remove(0);
cur.add(curNode.val);
if(curNode.left != null){
queue.add(curNode.left);
}
if(curNode.right != null){
queue.add(curNode.right);
}
}
res.add(cur);
}
return res;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(3);
root.left = new TreeNode(9);
root.right = new TreeNode(20);
root.right.left = new TreeNode(15);
root.right.right = new TreeNode(7);
TreeLevelOrder test = new TreeLevelOrder();
System.out.println(test.levelOrder(root));
}
}
回溯
77.组合
package backtracking;
import java.util.*;
public class Combine {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
if (k <= 0 || n < k) {
return res;
}
Deque<Integer> path = new ArrayDeque<>();
dfs(n, k, 1, res, path);
return res;
}
public void dfs(int n, int k, int begin, List<List<Integer>> res, Deque<Integer> path) {
if (path.size() == k) {
res.add(new ArrayList<>(path));
// System.out.println("res => " + res);
return;
}
// 只有这里 i <= n - (k - path.size()) + 1
for (int i = begin; i <= n - (k - path.size()) + 1; i++) {
path.add(i);
// System.out.println("递归之前 => " + path);
dfs(n, k, i + 1, res, path);
// System.out.println("递归之后 => " + path);
path.removeLast();
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// int n = sc.nextInt();
// int k = sc.nextInt();
int n = 4;
int k = 3;
Combine test = new Combine();
System.out.println(test.combine(n, k));
}
}
470.用Rand7()实现Rand10()
已知 rand_N() 可以等概率的生成[1, N]范围的随机数
那么:
(rand_X() - 1) × Y + rand_Y() ==> 可以等概率的生成[1, X * Y]范围的随机数
即实现了 rand_XY()
7 * 7 = 49 ,小于40取模10
/**
* 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 x = (rand7() - 1) * 7 + rand7();
if(x <= 40){
return x % 10 + 1;
}
}
}
}