/** * 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 reverseKGroup(ListNode list, int k) { // list可以看作是由若干个包含k个结点的子链表和一个不足k个结点的子链表组成 ListNode head = new ListNode(); // 1、头结点 head.next = list; ListNode left = head, right = head; // 2、子链表的前驱结点和后继结点 ListNode start, end; // 3、子链表的首结点与尾结点 while (true) { for (int i = 0; i < k && right != null; i++) { // 4、判断下一个子链表是否包含k个结点 right = right.next; // right指向子链表的第1个结点时,i=1 } // right指向子链表的第k个结点时,i=k,循环结束,但第k个结点未必存在 if (right == null) { // 下一个子链表不足k个结点,翻转完毕 break; } start = left.next; // 确定首结点 end = right; // 确定尾结点 right = right.next; // 确定后继结点 end.next = null; // 5、将子链表的尾结点与母表断开,以便于翻转 left.next = reverseList(start); // 6、返回子链表翻转后的首结点,即子链表原来的尾结点 start.next = right; // 7、将翻转后的子链表的尾结点(即子链表原来的首结点)与母表连接 left = start; // 确定前驱结点 right = start; // 8、复位right,以继续翻转下一个子链表 } return head.next; } public ListNode reverseList(ListNode head) { // 1、同时记录相邻的三个结点prev、curr和next,初始时prev为null,curr为head // 2、改变curr.next,使其指向prev // 3、"滑动窗口"右移一位,prev指向curr,curr指向next,curr不为null时,next指向next.next // 4、终止条件是curr为null,即curr指向链表末尾结点的下一个位置时结束 head = iteration(head); // 方法一:迭代法 // head = recursion(null, head); // 方法二:递归法 return head; } public ListNode iteration(ListNode head) { ListNode prev = null; ListNode curr = head; while (curr != null) { ListNode next = curr.next; curr.next = prev; prev = curr; curr = next; } return prev; } public ListNode recursion(ListNode prev, ListNode curr) { if (curr == null) { return prev; } ListNode next = curr.next; curr.next = prev; return recursion(curr, next); }}
class Solution { public int findKthLargest(int[] nums, int k) { int target = nums.length - k; // 数组排序后第k大元素的位置 int left = 0; int right = nums.length - 1; while (true) { int index = partition(nums, left, right); if (index == target) { return nums[index]; } else if (index < target) { // 基准位置小于目标位置时,对基准的右侧排序 left = index + 1; } else { // 基准位置大于目标位置时,对基准的左侧排序 right = index - 1; } } } public int partition(int[] nums, int left, int right) { int pivot = nums[left]; while (left < right) { while (left < right && pivot <= nums[right]) { right--; } nums[left] = nums[right]; while (left < right && pivot >= nums[left]) { left++; } nums[right] = nums[left]; } nums[left] = pivot; return left; }}
class Solution { public int[] sortArray(int[] nums) { bubbleSort(nums); // 冒泡排序 // quickSort(nums, 0, nums.length - 1); // 快速排序 // dumpSort(nums); // 堆排序 return nums; } public void bubbleSort(int[] nums) { for (int i = 1; i < nums.length; i++) { // 最多进行(arr.length-1)轮冒泡 boolean flag = false; // 若本轮有元素交换,则置为true,若本轮结束后仍为false,则说明上一轮过后数组已有序 for (int j = 0; j < nums.length - i; j++) { if (nums[j] > nums[j + 1]) { // 稳定排序,O(n2) nums[j] = nums[j] + nums[j + 1]; nums[j + 1] = nums[j] - nums[j + 1]; nums[j] = nums[j] - nums[j + 1]; flag = true; } } if (!flag) { break; } } } public void quickSort(int[] nums, int left, int right) { if (left < right) { // 最理想的划分是平均划分O(nlog2(n)),即分成两个规模为n/2的问题,最差划分是最大程度的不对称划分O(n2),即排序表基本有序或基本无序 int pivot = partition(nums, left, right); // pivot:基准、支点、枢轴、中心点 quickSort(nums, left, pivot - 1); quickSort(nums, pivot + 1, right); } } public int partition(int[] nums, int left, int right) { int pivot = nums[left]; // 直接取首元素为基准,即严蔚敏教材的算法,也可以随机选取基准以尽量避免最差的划分,此时称为随机快速排序 while (left < right) { while (left < right && pivot <= nums[right]) { // 必须是<=和>=,如果是<和>,那么当首尾元素等大时,会陷入死循环 right--; } nums[left] = nums[right]; // 将小于基准的元素与基准交换位置 while (left < right && pivot >= nums[left]) { // 快排不稳定,比如{2,1,2,1} left++; } nums[right] = nums[left]; // 将大于基准的元素与基准交换位置 } nums[left] = pivot; // 将基准放在它的最终位置上 return left; // 返回基准的最终位置,该位置左侧的元素均 ≤ 基准,该位置右侧的元素均 ≥ 基准 } public void dumpSort(int[] nums) { }}
class Solution { public int lengthOfLongestSubstring(String s) { HashMap<Character, Integer> hashMap = new HashMap<>(); // key为s中的字符,value是字符在s中的最新位置 int len = s.length(); int maxLen = 0; int start = 0; for (int end = 0; end < len; end++) { // [start,end]为不重复子串 char c = s.charAt(end); if (hashMap.containsKey(c)) { // start = map.get() + 1; // 输入"abba"时出错,即start指针不能往回走,必须一直向后走 start = Math.max(hashMap.get(c) + 1, start); // 前一个重复字符的下一个位置是新的不重复子串的起始位置 } maxLen = Math.max(maxLen, end - start + 1); hashMap.put(c, end); // 利用put()的覆盖写性质,巧妙地从映射表中“除去了”前一个重复字符 // map中会冗余存储开头的一部分字符,但除了这些冗余,其他字符都是新的不重复子串的字符 } return maxLen; }}
/** * 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); */class LRUCache { class DLinkedNode { // 双向链表,实现LRU(Least Recently Used,最近最少使用) int k; int v; DLinkedNode prev; DLinkedNode next; public DLinkedNode() { } public DLinkedNode(int key, int value) { k = key; v = value; } } private HashMap<Integer, DLinkedNode> cache = new HashMap<>(); // 哈希表,使存取复杂度为O(1) private int capacity; // 容量 private int size = 0; // 大小 private DLinkedNode head = new DLinkedNode(); // 头结点,不保存数据 private DLinkedNode tail = new DLinkedNode(); // 尾结点,不保存数据 public LRUCache(int capacity) { this.capacity = capacity; head.next = tail; // 初始时首尾相连 tail.prev = head; } public int get(int key) { DLinkedNode node = cache.get(key); if (node == null) { // key不存在于缓存中,返回-1 return -1; } else { // key存在于缓存中,返回其值 removeNode(node); // 先将最近访问结点从链表中删除 addToHead(node); // 再将最近访问结点移至链表首部 return node.v; } } public void put(int key, int value) { DLinkedNode node = cache.get(key); if (node == null) { // key不存在于缓存中,新增结点 node = new DLinkedNode(key, value); cache.put(key, node); addToHead(node); // 新增结点也是最近访问结点,将其移至链表首部 if (size > capacity) { // LRU缓存的大小达到容量上限,删除最近最少使用结点 cache.remove(tail.prev.k); removeNode(tail.prev); } } else { // key存在于缓存中,更新其值 node.v = value; removeNode(node); addToHead(node); } } private void removeNode(DLinkedNode node) { node.prev.next = node.next; node.next.prev = node.prev; size--; } private void addToHead(DLinkedNode node) { node.prev = head; node.next = head.next; head.next.prev = node; head.next = node; size++; }}
class LRUCache extends LinkedHashMap<Integer, Integer> { private int capacity; public LRUCache(int capacity) { super(capacity, 0.75F, true); this.capacity = capacity; } public int get(int key) { return super.getOrDefault(key, -1); } public void put(int key, int value) { super.put(key, value); } @Override protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) { return size() > capacity; }}


