1. 力扣2 两数相加
https://leetcode.cn/problems/add-two-numbers/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode p1 = l1;
ListNode p2 = l2;
ListNode dummy = new ListNode(-1);
ListNode p3 = dummy;
boolean mark = false;
while(p1 != null || p2 != null){
int num1 = 0;
int num2 = 0;
if(p1 != null){
num1 = p1.val;
p1 = p1.next;
}
if(p2 != null){
num2 = p2.val;
p2 = p2.next;
}
int sum = num1 + num2;
if(mark){
sum++;
mark = false;
}
if(sum >= 10){
mark = true;
sum -= 10;
}
p3.next = new ListNode(sum);
p3 = p3.next;
}
if(mark){
p3.next = new ListNode(1);
}
return dummy.next;
}
}
2. 力扣4 寻找两个正序数组的中位数
https://leetcode.cn/problems/median-of-two-sorted-arrays/
思路:
要求时间复杂度O(log(n)),不能排序,只能二分查找。
没什么思路,参照官方题解写的。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length + nums2.length;
int k = n / 2;
if(n % 2 == 1){
return findKthMin(nums1, nums2, k + 1);
} else{
return (findKthMin(nums1, nums2, k) + findKthMin(nums1, nums2, k + 1)) / 2.0;
}
}
public double findKthMin(int[] nums1, int[] nums2, int k){
int n1 = nums1.length;
int n2 = nums2.length;
int p1 = 0;
int p2 = 0;
while(true){
if(p1 == n1){
return nums2[p2 + k - 1];
}
if(p2 == n2){
return nums1[p1 + k - 1];
}
if(k == 1){
return Math.min(nums1[p1], nums2[p2]);
}
int ck = k / 2;
int k1 = Math.min(p1 + ck, n1) - 1;
int k2 = Math.min(p2 + ck, n2) - 1;
if(nums1[k1] <= nums2[k2]){
k -= k1 - p1 + 1;
p1 = k1 + 1;
} else{
k -= k2 - p2 + 1;
p2 = k2 + 1;
}
}
}
}
3. 力扣5 最长回文子串
https://leetcode.cn/problems/longest-palindromic-substring/
思路:
暴力求解。
class Solution {
public String longestPalindrome(String s) {
String res = "";
// 遍历字符串s
for(int i = 0; i < s.length(); i++){
String str1 = getPalindrome(s, i, i);
String str2 = getPalindrome(s, i, i + 1);
String str = str1.length() > str2.length() ? str1 : str2;
res = str.length() > res.length() ? str : res;
}
return res;
}
/**
* 获得以某两点为中心的最长子回文串
*/
public String getPalindrome(String s, int left, int right){
while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
left--;
right++;
}
return s.substring(left + 1, right);
}
}
4. 力扣7 整数反转
https://leetcode.cn/problems/reverse-integer/
思路:
这道题的卡点在于判断结果是否超出有符号整数范围。
class Solution {
public int reverse(int x) {
int res = 0;
while(x != 0){
if(res < Integer.MIN_VALUE / 10 || res > Integer.MAX_VALUE / 10){
return 0;
}
int curr = x % 10;
res = res * 10 + curr;
x /= 10;
}
return res;
}
}
5. 力扣8 字符串转换整数
https://leetcode.cn/problems/string-to-integer-atoi/
class Solution {
boolean b2 = true;
public int myAtoi(String s) {
String str1 = work1(s);
String str2 = work2(str1);
String str3 = work3(str2);
long long4 = work4(str3);
int int5 = work5(long4);
return int5;
}
public String work1(String s){
return s.trim();
}
public String work2(String s){
if("".equals(s)){
return s;
}
char c = s.charAt(0);
if(c == '-'){
b2 = false;
}
if(c == '-' || c == '+'){
return s.substring(1);
}
return s;
}
public String work3(String s){
int n = s.length();
int i = 0;
boolean firstNot0 = false;
StringBuilder sb = new StringBuilder();
while(i < n){
char c = s.charAt(i);
if(c >= '0' && c <= '9'){
if(c > '0'){
firstNot0 = true;
}
if(c != '0' || firstNot0){
sb.append(c);
}
i++;
} else{
break;
}
}
if(sb.length() == 0){
sb.append('0');
}
return sb.toString();
}
public long work4(String s){
// 防止s超出long类型的取值范围
if(s.length() > 10){
return b2 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
long l = Math.abs(Long.valueOf(s));
return b2 ? l : -l;
}
public int work5(long l){
if(l < Integer.MIN_VALUE){
l = Integer.MIN_VALUE;
}
if(l > Integer.MAX_VALUE){
l = Integer.MAX_VALUE;
}
return (int) l;
}
}
6. 力扣9 回文数
https://leetcode.cn/problems/palindrome-number/
思路:
将数字高低位倒过来,如果和原来的大小相等,就是回文数。
class Solution {
public boolean isPalindrome(int x) {
if(x < 0){
return false;
}
int d = x;
int sum = 0;
while(x != 0){
int curr = x % 10;
sum = sum * 10 + curr;
x /= 10;
}
return sum == d;
}
}
7. 力扣11 盛最多水的容器
https://leetcode.cn/problems/container-with-most-water/
思路:
双指针法。如果知道要使用双指针法,很容易写出代码,问题是,为什么这道题可以使用双指针法?
对撞双指针,每次都让两个指针中指向的值较小的指针移动,因为,假如指向较小值的指针固定,无论另外一个指针移动多少步,得到的盛水量都不可能大于当前盛水量。
class Solution {
public int maxArea(int[] height) {
int l = 0;
int r = height.length - 1;
int max = 0;
while(l <= r){
int curr = (r - l) * Math.min(height[l], height[r]);
if(curr > max){
max = curr;
}
if(height[l] < height[r]){
l++;
}else{
r--;
}
}
return max;
}
}
8. 力扣14 最长公共前缀
https://leetcode.cn/problems/longest-common-prefix/
class Solution {
public String longestCommonPrefix(String[] strs) {
boolean f = true;
StringBuilder sb = new StringBuilder();
int k = 0;
while(f){
if(k >= strs[0].length()){
break;
}
char c = strs[0].charAt(k);
for(int i = 1; i < strs.length; i++){
if(k >= strs[i].length() || strs[i].charAt(k) != c){
f = false;
break;
}
}
if(f){
sb.append(c);
k++;
}
}
return sb.toString();
}
}
9. 力扣15 三数之和
https://leetcode.cn/problems/3sum/submissions/
思路:
先排序。定下第一个值,剩下两个值使用对撞指针。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
List<List<Integer>> res = new LinkedList();
Arrays.sort(nums);
int p1 = 0;
while(p1 < n - 2){
if(p1 > 0 && nums[p1] == nums[p1 - 1]){
p1++;
continue;
}
int target = -nums[p1];
int p2 = p1 + 1;
int p3 = n - 1;
while(p2 < p3){
if(p2 > p1 + 1 && nums[p2] == nums[p2 - 1]){
p2++;
continue;
}
int sum = nums[p2] + nums[p3];
if(target > sum){
p2++;
} else if(target < sum){
p3--;
} else{
List<Integer> list = new LinkedList();
list.add(nums[p1]);
list.add(nums[p2]);
list.add(nums[p3]);
res.add(list);
p2++;
}
}
p1++;
}
return res;
}
}
10. 力扣16 最接近的三数之和
https://leetcode.cn/problems/3sum-closest/
class Solution {
public int threeSumClosest(int[] nums, int target) {
int n = nums.length;
Arrays.sort(nums);
int res = Integer.MAX_VALUE;
int minDert = Integer.MAX_VALUE;
int p1 = 0;
while(p1 < n - 2){
int currTarget = target - nums[p1];
int p2 = p1 + 1;
int p3 = n - 1;
while(p2 < p3){
int sum = nums[p2] + nums[p3];
if(sum == currTarget){
return target;
}
int dert = Math.abs(sum - currTarget);
if(dert < minDert){
minDert = dert;
res = sum + nums[p1];
}
if(sum < currTarget){
p2++;
}
if(sum > currTarget){
p3--;
}
}
p1++;
}
return res;
}
}
11. 力扣20 有效的括号
https://leetcode.cn/problems/valid-parentheses/
思路:
使用栈。
class Solution {
public boolean isValid(String s) {
int n = s.length();
Stack<Character> stack = new Stack();
for(int i = 0; i < n; i++){
char c = s.charAt(i);
if(c == '(' || c == '[' || c == '{'){
stack.push(c);
} else{
if(stack.isEmpty()){
return false;
}
char d = stack.pop();
if(c == ')' && d != '('){
return false;
}
if(c == ']' && d != '['){
return false;
}
if(c == '}' && d != '{'){
return false;
}
}
}
return stack.isEmpty();
}
}
12. 力扣21 合并两个有序链表
https://leetcode.cn/problems/merge-two-sorted-lists/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode curr = dummy;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
curr.next = list1;
list1 = list1.next;
} else{
curr.next = list2;
list2 = list2.next;
}
curr = curr.next;
}
if(list1 != null){
curr.next = list1;
}
if(list2 != null){
curr.next = list2;
}
return dummy.next;
}
}
13. 力扣23 合并K个升序链表
https://leetcode.cn/problems/merge-k-sorted-lists/
思路:
把所有链表放在一个队列中,每次取出两个链表进行合并,再将合并后的链表放回队列,直到剩下一个链表。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int n = lists.length;
ListNode res = null;
Queue<ListNode> queue = new LinkedList();
for(int i = 0; i < n; i++){
queue.offer(lists[i]);
}
while(!queue.isEmpty()){
ListNode node1 = queue.poll();
if(queue.isEmpty()){
res = node1;
break;
}
ListNode node2 = queue.poll();
queue.offer(mergeTwoLists(node1, node2));
}
return res;
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode curr = dummy;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
curr.next = list1;
list1 = list1.next;
} else{
curr.next = list2;
list2 = list2.next;
}
curr = curr.next;
}
if(list1 != null){
curr.next = list1;
}
if(list2 != null){
curr.next = list2;
}
return dummy.next;
}
}
14. 力扣26 删除有序数组中的重复项
https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
思路:
快慢指针。
class Solution {
public int removeDuplicates(int[] nums) {
int n = nums.length;
int fast = 1;
int slow = 0;
while(fast < n){
if(nums[fast] != nums[slow]){
swap(nums, slow + 1, fast);
slow++;
}
fast++;
}
return slow + 1;
}
public void swap(int[] nums, int a, int b){
int t = nums[a];
nums[a] = nums[b];
nums[b] = t;
}
}
15. 力扣33 搜索旋转排序数组
https://leetcode.cn/problems/search-in-rotated-sorted-array/
思路:
二分搜索。每次取中点会将区间分成两部分,一部分有序,另一部分为旋转排序数组,如果target不在有序的一边,就在另一边,以此缩小区间。
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = n - 1;
while(left <= right){
int mid = left + (right - left) / 2;
if(target == nums[mid]){
return mid;
}
if(nums[mid] >= nums[left]){
if(target < nums[mid] && target >= nums[left]){
right = mid - 1;
} else{
left = mid + 1;
}
} else{
if(target > nums[mid] && target <= nums[right]){
left = mid + 1;
} else{
right = mid - 1;
}
}
}
return -1;
}
}
16. 力扣43 字符串相乘
https://leetcode.cn/problems/multiply-strings/
思路:
十分暴力的暴力法。
class Solution {
public String multiply(String num1, String num2) {
int[] intnum1 = strToIntArr(num1);
int[] intnum2 = strToIntArr(num2);
String[] resArr = new String[intnum2.length];
for(int i = 0; i < intnum2.length; i++){
resArr[i] = intArrToString(multiplyOne(intnum1, intnum2[i]), i);
}
String res = "";
for(int i = 0; i < resArr.length; i++){
res = strAdd(res, resArr[i]);
}
return res;
}
public String strAdd(String num1, String num2){
int[] intnum1 = strToIntArr(num1);
int[] intnum2 = strToIntArr(num2);
int size = Math.max(intnum1.length, intnum2.length) + 1;
int[] res = new int[size];
int tmp = 0;
for(int i = 0; i < res.length; i++){
int addnum1 = i < intnum1.length ? intnum1[i] : 0;
int addnum2 = i < intnum2.length ? intnum2[i] : 0;
int sum = addnum1 + addnum2 + tmp;
res[i] = sum % 10;
tmp = sum / 10;
}
return intArrToString(res, 0);
}
public int[] strToIntArr(String str){
int n = str.length();
int[] res = new int[n];
for(int i = 0; i < n; i++){
res[n - 1 - i] = str.charAt(i) - '0';
}
return res; // 倒序
}
public int[] multiplyOne(int[] num, int k){
int n = num.length;
int tmp = 0;
int[] res = new int[n + 1];
for(int i = 0; i < n; i++){
int r = num[i] * k + tmp;
res[i] = r % 10;
tmp = r / 10;
}
res[n] = tmp;
return res;
}
public String intArrToString(int[] num, int move){
StringBuilder sb = new StringBuilder();
int start = num.length - 1;
while(start >= 0){
if(num[start] == 0){
start--;
continue;
}
break;
}
while(start >= 0){
sb.append(num[start]);
start--;
}
while(move > 0){
sb.append('0');
move--;
}
if(sb.isEmpty()){
sb.append('0');
}
return sb.toString();
}
}
17. 力扣46 全排列
https://leetcode.cn/problems/permutations/
思路:
一眼回溯。
class Solution {
List<List<Integer>> res;
List<Integer> tool;
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
res = new LinkedList();
tool = new LinkedList();
used = new boolean[nums.length];
backtrack(nums, used);
return res;
}
public void backtrack(int[] nums, boolean[] used){
if(tool.size() == nums.length){
res.add(new LinkedList(tool));
return;
}
for(int i = 0; i < nums.length; i++){
if(!used[i]){
tool.add(nums[i]);
used[i] = true;
backtrack(nums, used);
tool.remove(tool.size() - 1);
used[i] = false;
}
}
}
}
18. 力扣53 最大子数组和
https://leetcode.cn/problems/maximum-subarray/
思路:
一次遍历,当sum<0时,重新将sum置为0。
class Solution {
public int maxSubArray(int[] nums) {
int n = nums.length;
int res = Integer.MIN_VALUE;
int sum = 0;
for(int i = 0; i < n; i++){
sum += nums[i];
res = Math.max(res, sum);
if(sum < 0){
sum = 0;
}
}
return res;
}
}
19. 力扣54 螺旋矩阵
https://leetcode.cn/problems/spiral-matrix/
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
int h = matrix.length;
int w = matrix[0].length;
int upper_bound = 0;
int lower_bound = h - 1;
int left_bound = 0;
int right_bound = w - 1;
List<Integer> res = new ArrayList();
while(res.size() < h * w){
if(upper_bound <= lower_bound){
for(int i = left_bound; i <= right_bound; i++){
res.add(matrix[upper_bound][i]);
}
upper_bound++;
}
if(right_bound >= left_bound){
for(int i = upper_bound; i <= lower_bound; i++){
res.add(matrix[i][right_bound]);
}
right_bound--;
}
if(lower_bound >= upper_bound){
for(int i = right_bound; i >= left_bound; i--){
res.add(matrix[lower_bound][i]);
}
lower_bound--;
}
if(left_bound <= right_bound){
for(int i = lower_bound; i >= upper_bound; i--){
res.add(matrix[i][left_bound]);
}
left_bound++;
}
}
return res;
}
}
20. 力扣59 螺旋矩阵II
https://leetcode.cn/problems/spiral-matrix-ii/
class Solution {
public int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int left = 0;
int right = n - 1;
int top = 0;
int bottom = n - 1;
int curr = 1;
int i = 0;
int j = -1;
while(curr <= n * n){
if(i == top){
while(j < right){
j++;
res[i][j] = curr;
curr++;
}
top++;
}
if(j == right){
while(i < bottom){
i++;
res[i][j] = curr;
curr++;
}
right--;
}
if(i == bottom){
while(j > left){
j--;
res[i][j] = curr;
curr++;
}
bottom--;
}
if(j == left){
while(i > top){
i--;
res[i][j] = curr;
curr++;
}
left++;
}
}
return res;
}
}
21. 力扣61 旋转链表
https://leetcode.cn/problems/rotate-list/
思路:
链表在特定位置的断开、重连。
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null){
return null;
}
ListNode countNode = head;
int count = 0;
while(countNode != null){
count++;
countNode = countNode.next;
}
int step = k % count;
ListNode p1 = head;
ListNode p2 = head;
for(int i = 0; i < step; i++){
p2 = p2.next;
}
while(p2.next != null){
p1 = p1.next;
p2 = p2.next;
}
p2.next = head;
head = p1.next;
p1.next = null;
return head;
}
}
22. 力扣62 不同路径
https://leetcode.cn/problems/unique-paths/
思路:
基础的动态规划。
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(i == 0 || j == 0){
dp[i][j] = 1;
} else{
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
23. 力扣70 爬楼梯
https://leetcode.cn/problems/climbing-stairs/
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n];
for(int i = 0; i < n; i++){
if(i == 0){
dp[i] = 1;
} else if(i == 1){
dp[i] = 2;
} else{
dp[i] = dp[i - 1] + dp[i - 2];
}
}
return dp[n - 1];
}
}
24. 力扣78 子集
https://leetcode.cn/problems/subsets/
class Solution {
List<List<Integer>> res;
List<Integer> track;
public List<List<Integer>> subsets(int[] nums) {
res = new LinkedList();
track = new LinkedList();
backtrack(nums, 0);
return res;
}
public void backtrack(int[] nums, int start){
res.add(new LinkedList(track));
for(int i = start; i < nums.length; i++){
track.add(nums[i]);
backtrack(nums, i + 1);
track.remove(track.size() - 1);
}
}
}
25. 力扣88 合并两个有序数组
https://leetcode.cn/problems/merge-sorted-array/
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m - 1;
int p2 = n - 1;
int curr = m + n - 1;
while(curr >= 0){
if(p1 < 0){
nums1[curr] = nums2[p2];
p2--;
curr--;
continue;
}
if(p2 < 0){
nums1[curr] = nums1[p1];
p1--;
curr--;
continue;
}
if(nums1[p1] >= nums2[p2]){
nums1[curr] = nums1[p1];
p1--;
} else{
nums1[curr] = nums2[p2];
p2--;
}
curr--;
}
}
}
26. 力扣89 格雷编码
https://leetcode.cn/problems/gray-code/
思路:
没有思路,背公式。
class Solution {
public List<Integer> grayCode(int n) {
// 第i位格雷码:i / 2 ^ i
int pro = 1;
for(int i = 0; i < n; i++){
pro *= 2;
}
List<Integer> res = new LinkedList();
for(int i = 0; i < pro; i++){
res.add(i / 2 ^ i);
}
return res;
}
}
27. 力扣104 二叉树的最大深度
https://leetcode.cn/problems/maximum-depth-of-binary-tree/
class Solution {
public int maxDepth(TreeNode root){
if(root == null){
return 0;
}
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
28. 力扣121 买卖股票的最佳时机
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/
思路:
买卖股票的一系列题目都可以使用有限状态机来求解,对这道题来说有点小题大做。
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
int[] dp = new int[2];
// 0: 不持有, 1: 持有
dp[0] = 0;
dp[1] = -prices[0];
for(int i = 1; i < n; i++){
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
// 只许买一次, 所以是-prices[i]而不是dp[0]-prices[i]
dp[1] = Math.max(dp[1], -prices[i]);
}
return dp[0];
}
}
29. 力扣122 买卖股票的最佳时机II
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
int[] dp = new int[2];
dp[0] = 0;
dp[1] = - prices[0];
for (int i = 1; i < n; i++) {
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
}
return dp[0];
}
}
30. 力扣124 二叉树中的最大路径和
https://leetcode.cn/problems/binary-tree-maximum-path-sum/
思路:
遍历二叉树时,对每一个结点要做两件事:
1. 计算以该结点为路径的一个端点的最大路径和,供其父结点进行计算。
2. 计算以该结点为根结点的最大路径和,做全局比较。
比较以每个结点为根结点的最大路径和,得到全局最大路径和。
class Solution {
int res;
public int maxPathSum(TreeNode root) {
res = Integer.MIN_VALUE;
getMaxPathSum(root);
return res;
}
public int getMaxPathSum(TreeNode root){
if(root == null){
return 0;
}
int curr = root.val;
int left = getMaxPathSum(root.left);
int right = getMaxPathSum(root.right);
int maxPath = Math.max(Math.max(left, right), 0) + curr;
int currMax = Math.max(curr + left + right, maxPath);
if(currMax > res){
res = currMax;
}
return maxPath;
}
}
31. 力扣136 只出现一次的数字
https://leetcode.cn/problems/single-number/
思路:
一个数字与0做异或操作,得到它本身,与本身做异或操作,得0。
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for(int i : nums){
res ^= i;
}
return res;
}
}
32. 力扣141 环形链表
https://leetcode.cn/problems/linked-list-cycle/
class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null){
return false;
}
ListNode p1 = head;
ListNode p2 = head;
while(p1 != null && p1.next != null){
p1 = p1.next.next;
p2 = p2.next;
if(p1 == p2){
return true;
}
}
return false;
}
}
33. 力扣142 环形链表II
https://leetcode.cn/problems/linked-list-cycle-ii/
思路:
这里是使用哈希表解答。
官方题解有另一种很巧妙的方法,使用快慢指针,两指针相遇时,从相遇点和起点各启动一个新的指针,两个新指针相遇的点就是进入环形链表的点。
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> memo = new HashSet();
while(head != null){
if(memo.contains(head)){
return head;
}
memo.add(head);
head = head.next;
}
return null;
}
}
34. 力扣146 LRU缓存
https://leetcode.cn/problems/lru-cache/
思路:
使用哈希表+双向链表。
class ListNode{
int key;
int val;
ListNode pre;
ListNode next;
public ListNode(int key, int val){
this.key = key;
this.val = val;
}
}
class LRUCache {
int capacity;
Map<Integer, ListNode> map = new HashMap();
ListNode head = new ListNode(0, 0);
ListNode tail = new ListNode(0, 0);
public LRUCache(int capacity) {
this.capacity = capacity;
head.next = tail;
tail.pre = head;
}
public int get(int key) {
if(map.containsKey(key)){
ListNode node = map.get(key);
moveToFirst(node);
return node.val;
}
return -1;
}
public void put(int key, int value) {
if(map.containsKey(key)){
ListNode node = map.get(key);
node.val = value;
moveToFirst(node);
} else{
if(map.size() == capacity){
deleteLast();
}
ListNode newNode = new ListNode(key, value);
ListNode temp = head.next;
head.next = newNode;
newNode.pre = head;
newNode.next = temp;
temp.pre = newNode;
map.put(newNode.key, newNode);
}
}
public void deleteLast(){
ListNode last = tail.pre;
last.pre.next = tail;
tail.pre = last.pre;
map.remove(last.key);
}
public void moveToFirst(ListNode node){
node.pre.next = node.next;
node.next.pre = node.pre;
ListNode temp = head.next;
head.next = node;
node.pre = head;
node.next = temp;
temp.pre = node;
}
}
35. 力扣148 排序链表
https://leetcode.cn/problems/sort-list/
思路:
将链表分割成n个升序链表,依次合并。
class Solution {
public ListNode sortList(ListNode head) {
Queue<ListNode> queue = new LinkedList();
queue.offer(head);
ListNode pre = new ListNode(Integer.MIN_VALUE, head);
while(head != null){
if(head.val < pre.val){
queue.offer(head);
pre.next = null;
}
pre = head;
head = head.next;
}
while(!queue.isEmpty()){
ListNode node1 = queue.poll();
if(queue.isEmpty()){
return node1;
} else{
ListNode node2 = queue.poll();
queue.offer(mergeTwoLists(node1, node2));
}
}
return null;
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode curr = dummy;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
curr.next = list1;
list1 = list1.next;
} else{
curr.next = list2;
list2 = list2.next;
}
curr = curr.next;
}
if(list1 != null){
curr.next = list1;
}
if(list2 != null){
curr.next = list2;
}
return dummy.next;
}
}
36. 力扣155 最小栈
https://leetcode.cn/problems/min-stack/
思路:
维护两个栈,一个记录真实数值,另一个记录最小值。
class MinStack {
Stack<Integer> stack;
Stack<Integer> minStack;
public MinStack() {
stack = new Stack();
minStack = new Stack();
}
public void push(int val) {
stack.push(val);
minStack.push(minStack.isEmpty() ? val : Math.min(val, minStack.peek()));
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
37. 力扣160 相交链表
https://leetcode.cn/problems/intersection-of-two-linked-lists/
思路:
使用两个指针分别从两个链表的头部出发,当指针走到链表尾部时,移到另一个链表的头部,两指针相遇点即链表交点。
class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA;
ListNode p2 = headB;
while(p1 != p2){
if(p1 != null){
p1 = p1.next;
} else{
p1 = headB;
}
if(p2 != null){
p2 = p2.next;
} else{
p2 = headA;
}
}
return p1;
}
}
38. 力扣169 多数元素
https://leetcode.cn/problems/majority-element/
class Solution {
public int majorityElement(int[] nums) {
int n = nums.length;
Map<Integer, Integer> memo = new HashMap();
for(int i = 0; i < n; i++){
memo.put(nums[i], memo.getOrDefault(nums[i], 0) + 1);
if(memo.get(nums[i]) > n / 2){
return nums[i];
}
}
return -1;
}
}
39. 力扣206 反转链表
https://leetcode.cn/problems/reverse-linked-list/
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode node = reverseList(head.next);
head.next.next = head;
head.next = null;
return node;
}
}
40. 力扣215 数组中的第K个最大元素
https://leetcode.cn/problems/kth-largest-element-in-an-array/
思路:
没有梦想,用的人家的轮子。
class Solution {
public int findKthLargest(int[] nums, int k) {
int n = nums.length;
PriorityQueue<Integer> minHeap = new PriorityQueue();
for(int i = 0; i < n; i++){
minHeap.offer(nums[i]);
if(minHeap.size() > k){
minHeap.poll();
}
}
return minHeap.poll();
}
}
41. 力扣217 存在重复元素
https://leetcode.cn/problems/contains-duplicate/
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> set = new HashSet();
for(int i : nums){
if(set.contains(i)){
return true;
}
set.add(i);
}
return false;
}
}
42. 力扣230 二叉搜索树中第K小的元素
https://leetcode.cn/problems/kth-smallest-element-in-a-bst/
思路:
深度优先遍历,在中序位置计数。
class Solution {
int count = 0;
int res = 0;
public int kthSmallest(TreeNode root, int k) {
traverse(root, k);
return res;
}
public void traverse(TreeNode root, int k){
if(root == null){
return;
}
traverse(root.left, k);
count++;
if(count == k){
res = root.val;
}
traverse(root.right, k);
}
}
43. 力扣231 2的幂
https://leetcode.cn/problems/power-of-two/
思路:
位运算,2的幂只有一位是1,其他位都是0,2的幂减一的每个位都是1,且比2的幂少一位,两者做与运算得0。
class Solution {
public boolean isPowerOfTwo(int n) {
return n > 0 && (n & (n - 1)) == 0;
}
}
44. 力扣235 二叉搜索树的最近公共祖先
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/
思路:
公共祖先比一个结点的值大,比另一个结点的值小,或者就是两个结点之一。从根结点向下遍历即可。
class Solution {
TreeNode mark;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
traverse(root, p.val, q.val);
return mark;
}
public void traverse(TreeNode root, int p, int q){
if(root == null){
return;
}
if(p < root.val && q < root.val){
traverse(root.left, p, q);
} else if(p > root.val && q > root.val){
traverse(root.right, p, q);
} else{
mark = root;
}
}
}
45. 力扣236 二叉树的最近公共祖先
https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/
思路:
对每个结点来说,在其左子树上找p或q,然后再在其右子树上找p或q,如果在一棵子树上找到了p,在另一棵子树上找到了q,说明该结点是最近公共祖先。如果在同一棵子树上找到了p和q,说明该结点是公共祖先,但不是最近的,再去判断找到p和q的子树的根结点是否是最近公共祖先。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
return traverse(root, p, q);
}
public TreeNode traverse(TreeNode root, TreeNode p, TreeNode q){
if(root == null){
return root;
}
if(root == p || root == q){
return root;
}
TreeNode left = traverse(root.left, p, q);
TreeNode right = traverse(root.right, p, q);
if(left != null && right != null){
return root;
} else{
return left != null ? left : right;
}
}
}
46. 力扣237 删除链表中的结点
https://leetcode.cn/problems/delete-node-in-a-linked-list/
思路:
官方题解不讲武德,是在下输了。
class Solution {
public void deleteNode(ListNode node) {
node.val = node.next.val;
node.next = node.next.next;
}
}
47. 力扣238 除自身以外数组的乘积
https://leetcode.cn/problems/product-of-array-except-self/
思路:
正序计算累乘积数组,再倒序计算累乘积数组,结果数组的每个元素一定是两个累乘积数组中的元素的乘积。
class Solution {
public int[] productExceptSelf(int[] nums) {
int n = nums.length;
int[] arr1 = new int[n + 1];
int[] arr2 = new int[n + 1];
arr1[0] = 1;
for(int i = 1; i < n + 1; i++){
arr1[i] = arr1[i - 1] * nums[i - 1];
}
arr2[n] = 1;
for(int j = n - 1; j >= 0; j--){
arr2[j] = arr2[j + 1] * nums[j];
}
int[] answer = new int[n];
for(int k = 0; k < n; k++){
answer[k] = arr1[k] * arr2[k + 1];
}
return answer;
}
}
48. 力扣292 Nim游戏
https://leetcode.cn/problems/nim-game/
class Solution {
public boolean canWinNim(int n) {
return n % 4 != 0;
}
}
49. 力扣344 反转字符串
https://leetcode.cn/problems/reverse-string/
class Solution {
public void reverseString(char[] s) {
int n = s.length;
int mid = n / 2;
for(int i = 0; i <= mid - 1; i++){
swap(s, i, n - i - 1);
}
}
public void swap(char[] s, int a, int b){
char temp = s[a];
s[a] = s[b];
s[b] = temp;
}
}
50. 力扣557 反转字符串中的单词III
https://leetcode.cn/problems/reverse-words-in-a-string-iii/
class Solution {
public String reverseWords(String s) {
String[] ss = s.split(" ");
int n = ss.length;
for(int i = 0; i < n; i++){
ss[i] = reverseString(ss[i]);
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++){
if(i != 0){
sb.append(" ");
}
sb.append(ss[i]);
}
return sb.toString();
}
public String reverseString(String s) {
char[] cs = s.toCharArray();
int n = cs.length;
int mid = n / 2;
for(int i = 0; i <= mid - 1; i++){
swap(cs, i, n - i - 1);
}
return new String(cs);
}
public void swap(char[] cs, int a, int b){
char temp = cs[a];
cs[a] = cs[b];
cs[b] = temp;
}
}