刷题挑战链接
链表
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM1
反转链表
三指针迭代(pre/cur/next)
O(n)
O(1)
循环不变式清晰,边界处理简洁
🔗 直达
BM2
链表内指定区间反转
虚拟头节点 + 局部头插反转
O(n)
O(1)
两次遍历,定位后原地翻转
🔗 直达
BM3
每 k 个一组翻转
递归 + 尾插反转
O(n)
O(1)
tail 指针定位每组末尾,递归剩余
🔗 直达
BM4
合并两个排序链表
双指针归并
O(n)
O(1)
哑节点统一头结点处理
🔗 直达
BM5
合并 k 个排序链表
分治法两两合并
O(n log k)
O(log k)
复用 BM4,分治思想
🔗 直达
BM6
判断链表是否有环
快慢指针 / 哈希表
O(n)
O(1) / O(n)
快慢指针相遇判环,空间可选
🔗 直达
BM7
链表中环的入口
哈希表记录首次出现
O(n)
O(n)
再次遇到即入口,写法直观
🔗 直达
BM8
链表中倒数第 k 个节点
快慢指针
O(n)
O(1)
快指针先走 k 步,再同步
🔗 直达
BM9
删除倒数第 n 个节点
快慢指针 / 长度法
O(n)
O(1)
虚拟头节点避免头结点特判
🔗 直达
BM10
两个链表的第一个公共节点
哈希表存访问记录
O(n)
O(n)
先存一条链,再扫另一条
🔗 直达
BM11
链表相加(二)
翻转相加再翻转
O(n)
O(1)
两次翻转省去逆序存储
🔗 直达
BM12
单链表的排序
归并排序(链表版)
O(n log n)
O(log n)
快慢指针找中点,递归合并
🔗 直达
BM13
判断回文结构
快慢指针 + 后半翻转
O(n)
O(1)
翻转后半段后双指针比对
🔗 直达
BM14
链表的奇偶重排
双指针分离再拼接
O(n)
O(1)
一次遍历,奇偶指针交替
🔗 直达
BM15
删除有序链表中重复元素-I
单指针跳过重复
O(n)
O(1)
有序特性,直接 next 跳过
🔗 直达
BM16
删除有序链表中重复元素-II
虚拟头节点 + 一次遍历
O(n)
O(1)
出现重复值整段删除,保证无重复
🔗 直达
✅ 建议复习顺序(由易到难):
BM1 → BM4 → BM8 → BM9 → BM2 → BM3 → BM14 → BM15 → BM16 → BM6 → BM7 → BM10 → BM11 → BM12 → BM13 → BM5
BM1反转链表
反转链表_牛客题霸_牛客网https://www.nowcoder.com/practice/75e878df47f24fdc9dc3e400ec6058ca?tpId=295&tqId=23286&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public ListNode ReverseList (ListNode head) { if (head == null ) return null ; ListNode pre = null ; ListNode cur = head; while (cur != null ){ ListNode nextNode = cur.next; cur.next = pre; pre = cur; cur = nextNode; } return pre; } }
BM2链表内指定区间反转
链表内指定区间反转_牛客题霸_牛客网https://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c?tpId=295&sfm=html&channel=nowcoder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public ListNode reverseBetween (ListNode head, int m, int n) { ListNode res = new ListNode (-1 ); res.next = head; ListNode pre = res; ListNode cur = head; for (int i = 1 ; i < m; i++) { pre = cur; cur = cur.next; } for (int i = m; i < n; i++) { ListNode nextNode = cur.next; cur.next = nextNode.next; nextNode.next = pre.next; pre.next = nextNode; } return res.next; } }
BM3链表中的节点每k个一组翻转
链表中的节点每k个一组翻转_牛客题霸_牛客网https://www.nowcoder.com/practice/b49c3dc907814e9bbfa8437c251b028e?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public ListNode reverseKGroup (ListNode head, int k) { ListNode tail = head; for (int i = 0 ; i < k ; i ++){ if (tail == null ){ return head; } tail = tail.next; } ListNode pre = null ; ListNode cur = head; while (cur != tail){ ListNode nextNode = cur.next; cur.next = pre; pre = cur; cur = nextNode; } head.next = reverseKGroup(tail,k); return pre; } }
BM4 合并两个排序的链表
https://www.nowcoder.com/practice/d8b6b4358f774294a89de2a6ac4d9337?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public ListNode Merge (ListNode l1, ListNode l2) { if (l1 == null ) return l2; if (l2 == null ) return l1; ListNode head = new ListNode (-1 ); ListNode cur = head; while (l1 != null && l2 != null ){ if (l1.val < l2.val){ cur.next = l1; l1 = l1.next; }else { cur.next = l2; l2 = l2.next; } cur = cur.next; } if (l1 != null ) cur.next = l1; else cur.next = l2; return head.next; } }
BM5 合并k个已排序的链表
https://www.nowcoder.com/practice/65cfde9e5b9b4cf2b6bafa5f3ef33fa6?tpId=295&tqId=724&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.*;public class Solution { public ListNode mergeKLists (ArrayList<ListNode> lists) { return divideMerge(lists, 0 , lists.size() - 1 ); } ListNode divideMerge (ArrayList<ListNode> lists, int l, int r) { if (l > r) return null ; else if (l == r) return lists.get(l); int mid = (l + r) / 2 ; return Merge(divideMerge(lists, l, mid), divideMerge(lists, mid + 1 , r)); } ListNode Merge (ListNode list1, ListNode list2) { if (list1 == null ) return list2; if (list2 == null ) return list1; ListNode head = new ListNode (0 ); ListNode cur = head; while (list1 != null && list2 != null ) { if (list1.val <= list2.val) { cur.next = list1; list1 = list1.next; } else { cur.next = list2; list2 = list2.next; } cur = cur.next; } if (list1 != null ) cur.next = list1; else cur.next = list2; return head.next; } }
BM6 判断链表中是否有环
https://www.nowcoder.com/practice/650474f313294468a4ded3ce0f7898b9?tpId=295&tqId=605&sourceUrl=%2Fexam%2Foj
双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public boolean hasCycle (ListNode head) { if (head == null ) return false ; ListNode f = head; ListNode s = head; while (f != null && s != null ){ s = s.next; if (f.next != null ){ f = f.next.next; }else { return false ; } if (s == f) return true ; } return false ; } }
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public boolean hasCycle (ListNode head) { ListNode pos = head; Set<ListNode> vis = new HashSet <ListNode>(); while (pos != null ) { if (vis.contains(pos)) { return true ; } else { vis.add(pos); } pos = pos.next; } return false ; } }
BM7 链表中环的入口结点
链表中环的入口结点_牛客题霸_牛客网https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Solution { public ListNode EntryNodeOfLoop (ListNode pHead) { ListNode pos = pHead; Set<ListNode> cur = new HashSet <ListNode>(); while (pos != null ){ if (cur.contains(pos)){ return pos; }else { cur.add(pos); } pos = pos.next; } return null ; } }
BM8 链表中倒数最后k个结点
链表中倒数最后k个结点_牛客题霸_牛客网 https://www.nowcoder.com/practice/886370fe658f41b498d40fb34ae76ff9?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年7月28日19:04:44 —— 2025年7月28日19:09:22
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public ListNode FindKthToTail (ListNode pHead, int k) { ListNode s = pHead; ListNode f = pHead; int i = 0 ; for (; i < k ; i ++){ if (f == null ){ return null ;} f = f.next; } if (i == k && f == null ) return s; while (s != null && f != null ){ if (s.next != null && f.next == null ){ return s.next; } s = s.next; f = f.next; } return null ; } }
BM9 删除链表的倒数第n个节点
删除链表的倒数第n个节点_牛客题霸_牛客网https://www.nowcoder.com/practice/f95dcdafbde44b22a6d741baf71653f6?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年7月28日19:15:17 2025年7月28日19:31:54
双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public ListNode removeNthFromEnd (ListNode head, int n) { if (head == null ) return null ; ListNode s = head; ListNode f = head; for (int i = 0 ; i < n ; i ++){ f = f.next; } if ( f == null ) return head.next; while (f.next != null ){ f = f.next; s = s.next; } s.next = s.next.next; return head; } }
计算长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.*;public class Solution { public ListNode removeNthFromEnd (ListNode head, int n) { int lens = 0 ; ListNode p = head; ListNode q = head; while (q != null ){ lens ++; q = q.next; } if (lens < 2 ){ return null ; } if ( n == lens){ return head.next; } int i = 0 ; while (p != null ){ i ++; if (i == lens - n){ p.next = p.next.next; } p = p.next; } return head; } }
BM10 两个链表的第一个公共结点
两个链表的第一个公共结点_牛客题霸_牛客网https://www.nowcoder.com/practice/6ab1d9a29e88450685099d45c9e31e46?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public ListNode FindFirstCommonNode (ListNode pHead1, ListNode pHead2) { Set<ListNode> p1 = new HashSet <ListNode>(); while (pHead1 != null ){ p1.add(pHead1); pHead1 = pHead1.next; } while (pHead2 != null ){ if (p1.contains(pHead2)){ return pHead2; }else { pHead2 = pHead2.next; } } return null ; } }
BM11 链表相加(二)
链表相加(二)_牛客题霸_牛客网https://www.nowcoder.com/practice/c56f6c70fb3f4849bc56e33ff2a50b6b?tpId=295&tqId=1008772&sourceUrl=%2Fexam%2Foj 2025年7月30日22:32:01 2025年7月30日22:58:52
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.*;public class Solution { public ListNode addInList (ListNode head1, ListNode head2) { if (head1 == null ) return head2; if (head2 == null ) return head1; head1 = ReverseList(head1); head2 = ReverseList(head2); ListNode res = new ListNode (-1 ); ListNode head = res; int carry = 0 ; while (head1 != null || head2 != null || carry != 0 ){ int v1 = (head1 == null ? 0 : head1.val); int v2 = (head2 == null ? 0 : head2.val); int temp = v1 + v2 + carry; carry = temp / 10 ; head.next = new ListNode (temp % 10 ); head = head.next; if (head1 != null ) head1 = head1.next; if (head2 != null ) head2 = head2.next; } return ReverseList(res.next); } }
BM12 单链表的排序
单链表的排序_牛客题霸_牛客网https://www.nowcoder.com/practice/f23604257af94d939848729b1a5cda08?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年7月30日23:01:29
归并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { ListNode merge (ListNode ph1, ListNode ph2) { if (ph1 == null ) return ph2; if (ph2 == null ) return ph1; ListNode head = new ListNode (0 ); ListNode cur = head; while (ph1 != null && ph2 != null ){ if (ph1.val <= ph2.val){ cur.next = ph1; ph1 =ph1.next; }else { cur.next = ph2; ph2 = ph2.next; } cur = cur.next; } if (ph1 != null ) cur.next = ph1; else cur.next = ph2; return head.next; } public ListNode sortInList (ListNode head) { if (head == null || head.next == null ) return head; ListNode left = head; ListNode mid = head.next; ListNode right = head.next.next; while (right != null && right.next != null ){ left = left.next; mid = mid.next; right = right.next.next; } left.next = null ; return merge(sortInList(head),sortInList(mid)); } }
BM13 判断一个链表是否为回文结构
判断一个链表是否为回文结构_牛客题霸_牛客网https://www.nowcoder.com/practice/3fed228444e740c8be66232ce8b87c2f?tpId=295&tqId=1008769&sourceUrl=%2Fexam%2Foj
双指针 + 中点翻转遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;public class Solution { ListNode reverse (ListNode head) { ListNode pre = null ; while (head != null ){ ListNode curNext = head.next; head.next = pre; pre = head; head = curNext; } return pre; } public boolean isPail (ListNode head) { if (head == null ) return true ; ListNode f = head; ListNode s = head; while (f != null && f.next != null ){ f = f.next.next; s = s.next; } s = reverse(s); f = head; while (s != null && f != null ){ if (s.val != f.val) return false ; s = s.next; f = f.next; } return true ; } }
借助额外空间 - 栈做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public boolean isPail (ListNode head) { Stack<Integer> st = new Stack (); ListNode cur = head; while (cur != null ){ st.push(cur.val); cur = cur.next; } while (head != null ){ if (st.pop() != head.val) return false ; head = head.next; } return true ; } }
借助额外空间 - 链表做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public boolean isPail (ListNode head) { List<Integer> list = new ArrayList (); while (head != null ){ list.add(head.val); head = head.next; } int n = list.size(); for (int i = 0 ; i < n / 2 ; i ++){ if (list.get(i).equals(list.get(n - i - 1 )) == false ) return false ; } return true ; } }
BM14 链表的奇偶重排
链表的奇偶重排_牛客题霸_牛客网https://www.nowcoder.com/practice/02bf49ea45cd486daa031614f9bd6fc3?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public ListNode oddEvenList (ListNode head) { if (head == null ) return head; ListNode even = head.next; ListNode odd = head; ListNode evenHead = even; while (even != null && even.next != null ){ odd.next = even.next; odd = odd.next; even.next = odd.next; even = even.next; } odd.next = evenHead; return head; } }
BM15 删除有序链表中重复的元素-I
删除有序链表中重复的元素-I_牛客题霸_牛客网https://www.nowcoder.com/practice/c087914fae584da886a0091e877f2c79?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.*;public class Solution { public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; ListNode cur = head; while (cur != null && cur.next != null ){ if (cur.next.val == cur.val) cur.next = cur.next.next; else cur = cur.next; } return head; } }
BM16 删除有序链表中重复的元素-II
删除有序链表中重复的元素-II_牛客题霸_牛客网https://www.nowcoder.com/practice/71cef9f8b5564579bf7ed93fbe0b2024?tpId=295&tqId=663&sourceUrl=%2Fexam%2Foj
虚拟头结点 + 遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; ListNode res = new ListNode (-1 ); res.next = head; ListNode cur = res; while (cur.next != null && cur.next.next != null ){ if (cur.next.val == cur.next.next.val){ int temp = cur.next.val; while (cur.next != null && cur.next.val == temp){ cur.next = cur.next.next; } }else { cur = cur.next; } } return res.next; } }
借助哈希表计数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public ListNode deleteDuplicates (ListNode head) { if (head == null ) return null ; Map<Integer,Integer> mp = new HashMap <>(); ListNode cur = head; while (cur != null ){ mp.merge(cur.val,1 ,Integer::sum); cur = cur.next; } ListNode res = new ListNode (-1 ); res.next = head; cur = res; while (cur.next != null ){ if (mp.get(cur.next.val) != 1 ){ cur.next = cur.next.next; }else { cur = cur.next; } } return res.next; } }
二分查找/排序
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM17
二分查找-I
二分查找,不断缩小搜索范围
O(logn)
O(1)
使用位运算优化中点计算,逻辑清晰
🔗 直达
BM18
二维数组中的查找
从左下角或右上角开始查找,利用二维数组的有序性
O(m+n)
O(1)
选择合适的起点,避免重复比较,逻辑简洁
🔗 直达
BM19
寻找峰值
二分查找,利用峰值的性质
O(logn)
O(1)
使用二分查找快速定位峰值,逻辑清晰
🔗 直达
BM20
数组中的逆序对
归并排序,在合并过程中统计逆序对
O(nlogn)
O(n)
使用归并排序优化逆序对统计,逻辑简洁
🔗 直达
BM21
旋转数组的最小数字
二分查找,利用旋转数组的性质
O(logn)
O(1)
使用二分查找快速定位最小值,逻辑清晰
🔗 直达
BM22
比较版本号
按点分隔版本号,逐段比较
O(n)
O(1)
逐段比较版本号,逻辑简洁
🔗 直达
✅ 建议复习顺序(由易到难):
BM17 → BM18 → BM19 → BM21 → BM20 → BM22
BM17 二分查找-I
二分查找-I_牛客题霸_牛客网https://www.nowcoder.com/practice/d3df40bd23594118b57554129cadf47b?tpId=295&tqId=1499549&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int search (int [] nums, int target) { int l = 0 ; int r = nums.length - 1 ; while (l <= r){ int mid = (l + r) >> 1 ; if (nums[mid] == target) return mid; else if (nums[mid] > target) r = mid - 1 ; else l = mid + 1 ; } return -1 ; } }
BM18 二维数组中的查找
二维数组中的查找_牛客题霸_牛客网https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Solution { public boolean Find (int target, int [][] array) { if (array.length == 0 ) return false ; int n = array.length; if (array[0 ].length == 0 ) return false ; int m = array[0 ].length; for (int i = n - 1 , j = 0 ; i >= 0 && j < m; ) { if (array[i][j] > target) i--; else if (array[i][j] < target) j++; else return true ; } return false ; } }
BM19 寻找峰值
寻找峰值_牛客题霸_牛客网https://www.nowcoder.com/practice/fcf87540c4f347bcb4cf720b5b350c76?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Solution { public boolean Find (int target, int [][] array) { if (array.length == 0 ) return false ; int n = array.length; if (array[0 ].length == 0 ) return false ; int m = array[0 ].length; for (int i = n - 1 , j = 0 ; i >= 0 && j < m; ) { if (array[i][j] > target) i--; else if (array[i][j] < target) j++; else return true ; } return false ; } }
BM20 数组中的逆序对
数组中的逆序对_牛客题霸_牛客网https://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Solution { public int mod = 1000000007 ; public int mergeSort (int left, int right, int [] data, int [] temp) { if (left >= right) return 0 ; int mid = (left + right) / 2 ; int res = mergeSort(left, mid, data, temp) + mergeSort(mid + 1 , right, data, temp); res %= mod; int i = left, j = mid + 1 ; for (int k = left; k <= right; k++) temp[k] = data[k]; for (int k = left; k <= right; k++) { if (i == mid + 1 ) data[k] = temp[j++]; else if (j == right + 1 || temp[i] <= temp[j]) data[k] = temp[i++]; else { data[k] = temp[j++]; res += mid - i + 1 ; } } return res % mod; } public int InversePairs (int [] array) { int n = array.length; int [] res = new int [n]; return mergeSort(0 , n - 1 , array, res); } }
BM21 旋转数组的最小数字
旋转数组的最小数字_牛客题霸_牛客网https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId=295&tqId=23269&sourceUrl=%2Fexam%2Foj
暴力 + Stream流
1 2 3 4 5 6 7 8 9 import java.util.*;public class Solution { public int minNumberInRotateArray (int [] nums) { return Arrays.stream(nums).min().getAsInt(); } }
二分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public int minNumberInRotateArray (int [] nums) { if (nums.length == 0 ) return 0 ; int l = 0 ; int r = nums.length - 1 ; while (l < r){ int mid = (l + r) / 2 ; if (nums[mid] < nums[r]) r = mid; else if (nums[mid] > nums[r]) l = mid + 1 ; else r --; } return nums[l]; } }
BM22 比较版本号
比较版本号_牛客题霸_牛客网https://www.nowcoder.com/practice/2b317e02f14247a49ffdbdba315459e7?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import java.util.*;public class Solution { public int compare (String v1, String v2) { int n1 = v1.length(); int n2 = v2.length(); int i = 0 , j = 0 ; while (i < n1 || j < n2) { long num1 = 0 ; long num2 = 0 ; while (i < n1 && v1.charAt(i) != '.' ) { num1 = num1 * 10 + (v1.charAt(i) - '0' ); i++; } i++; while (j < n2 && v2.charAt(j) != '.' ) { num2 = num2 * 10 + (v2.charAt(j) - '0' ); j++; } j++; if (num1 > num2) return 1 ; else if (num1 < num2) return -1 ; } return 0 ; } }
二叉树
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM23
二叉树的前序遍历
递归实现,先访问根节点,再递归遍历左子树,最后递归遍历右子树
O(n)
O(n)
使用辅助函数 preorder
,逻辑清晰,递归终止条件明确
🔗 直达
BM24
二叉树的中序遍历
递归实现,先递归遍历左子树,访问根节点,再递归遍历右子树
O(n)
O(n)
递归逻辑简洁,通过辅助函数 inorder
实现
🔗 直达
BM25
二叉树的后序遍历
递归实现,先递归遍历左子树,再递归遍历右子树,最后访问根节点
O(n)
O(n)
递归逻辑清晰,辅助函数 postorder
实现后序遍历
🔗 直达
BM26
求二叉树的层序遍历
使用队列实现广度优先搜索,逐层访问节点
O(n)
O(n)
使用队列存储待访问的节点,逐层处理
🔗 直达
BM27
按之字形顺序打印二叉树
层序遍历结合反转操作,偶数层反转当前层的节点值
O(n)
O(n)
使用队列实现层序遍历,通过 Collections.reverse
反转偶数层
🔗 直达
BM28
二叉树的最大深度
使用队列实现广度优先搜索,逐层访问节点,计算最大深度
O(n)
O(n)
使用队列存储待访问的节点,逐层处理,每层深度加1
🔗 直达
BM29
二叉树中和为某一值的路径(一)
递归或广度优先搜索,记录从根节点到叶子节点的路径和
O(n)
O(n)
递归方法简洁,广度优先搜索使用 Pair
类记录路径和
🔗 直达
BM30
二叉搜索树与双向链表
递归或非递归中序遍历,将二叉搜索树转换为双向链表
O(n)
O(n)
递归方法中使用全局变量 head
和 pre
,非递归方法使用栈
🔗 直达
BM31
对称的二叉树
递归或层序遍历,判断二叉树是否对称
O(n)
O(n)
递归方法中使用辅助函数 chk
,层序遍历使用队列
🔗 直达
BM32
合并二叉树
递归合并两棵二叉树,对应节点值相加
O(n)
O(n)
递归方法简洁,新建节点 head
作为合并后的根节点
🔗 直达
BM33
二叉树的镜像
递归或栈实现,交换每个节点的左右子树
O(n)
O(n)
递归方法简洁,栈方法使用迭代
🔗 直达
BM34
判断是不是二叉搜索树
递归或中序遍历,判断中序遍历结果是否递增
O(n)
O(n)
递归方法中使用全局变量 pre
,中序遍历方法使用栈
🔗 直达
BM35
判断是不是完全二叉树
使用队列实现层序遍历,检查是否为完全二叉树
O(n)
O(n)
使用队列存储待访问的节点,逐层处理
🔗 直达
BM36
判断是不是平衡二叉树
递归计算子树高度,判断是否平衡
O(n)
O(n)
使用辅助函数 depth
,递归计算子树高度
🔗 直达
BM37
二叉搜索树的最近公共祖先
递归或路径比较,找到最近公共祖先
O(n)
O(n)
使用辅助函数 getPath
,记录路径
🔗 直达
BM38
在二叉树中找到两个节点的最近公共祖先
递归或路径比较,找到最近公共祖先
O(n)
O(n)
使用辅助函数 lowestCommonAncestor
,递归查找
🔗 直达
BM39
序列化二叉树
递归或层序遍历,序列化二叉树
O(n)
O(n)
使用辅助函数 SerializeFuction
和 DeserializeFuction
🔗 直达
BM40
重建二叉树
递归或栈遍历,根据前序和中序遍历重建二叉树
O(n)
O(n)
使用辅助函数 buildTree
,递归重建
🔗 直达
BM41
输出二叉树的右视图
递归或层序遍历,输出二叉树的右视图
O(n)
O(n)
使用辅助函数 rightSideView
,层序遍历
🔗 直达
✅ 建议复习顺序(由易到难):
BM23 → BM24 → BM25 → BM26 → BM27 → BM29 → BM30 → BM31 → BM32 → BM33 → BM34 → BM35 → BM36 → BM37 → BM38 → BM39 → BM40 → BM41
BM23 二叉树的前序遍历
二叉树的前序遍历_牛客题霸_牛客网https://www.nowcoder.com/practice/5e2135f4d2b14eb8a5b06fab4c938635?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.*;public class Solution { void preorder (List<Integer> list, TreeNode root) { if (root == null ) return ; list.add(root.val); preorder(list,root.left); preorder(list,root.right); } public int [] preorderTraversal (TreeNode root) { List<Integer> list = new ArrayList (); preorder(list,root); int [] res = new int [list.size()]; for (int i = 0 ; i < list.size(); i ++) res[i] = list.get(i); return res; } }
BM24 二叉树的中序遍历
二叉树的中序遍历_牛客题霸_牛客网https://www.nowcoder.com/practice/0bf071c135e64ee2a027783b80bf781d?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { void inorder (ArrayList<Integer> list, TreeNode root) { if (root == null ) return ; inorder(list,root.left); list.add(root.val); inorder(list,root.right); } public int [] inorderTraversal (TreeNode root) { ArrayList<Integer> list = new ArrayList <>(); inorder(list,root); int [] res = new int [list.size()]; for (int i = 0 ; i < list.size() ; i ++){ res[i] = list.get(i); } return res; } }
BM25 二叉树的后序遍历
二叉树的后序遍历_牛客题霸_牛客网https://www.nowcoder.com/practice/1291064f4d5d4bdeaefbf0dd47d78541?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { void postorder (ArrayList<Integer> list, TreeNode root) { if (root == null ) return ; postorder(list,root.left); postorder(list,root.right); list.add(root.val); } public int [] postorderTraversal (TreeNode root) { ArrayList<Integer> list = new ArrayList <Integer>(); postorder(list,root); int [] res = new int [list.size()]; for (int i = 0 ; i < list.size() ; i ++) res[i] = list.get(i); return res; } }
BM26 求二叉树的层序遍历
求二叉树的层序遍历_牛客题霸_牛客网https://www.nowcoder.com/practice/04a5560e43e24e9db4595865dc9c63a3?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) { ArrayList<ArrayList<Integer>> res = new ArrayList (); if (root == null ) return res; Queue<TreeNode> q = new ArrayDeque <TreeNode> (); q.add(root); while (!q.isEmpty()){ ArrayList<Integer> row = new ArrayList (); int n = q.size(); for (int i = 0 ; i < n ; i ++){ TreeNode cur = q.poll(); row.add(cur.val); if (cur.left != null ) q.add(cur.left); if (cur.right != null ) q.add(cur.right); } res.add(row); } return res; } }
BM27 按之字形顺序打印二叉树
按之字形顺序打印二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/91b69814117f4e8097390d107d2efbe0?tpId=295&tqId=644&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
直接利用队列 广搜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.*;public class Solution { public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) { TreeNode h = pRoot; ArrayList<ArrayList<Integer>> res = new ArrayList <ArrayList<Integer>>(); if (h == null ) return res; Queue<TreeNode> q = new LinkedList <TreeNode>(); q.offer(h); int f = 0 ; while (!q.isEmpty()){ ArrayList<Integer> row = new ArrayList <>(); int n = q.size(); for (int i = 0 ; i < n ; i ++){ TreeNode cur = q.poll(); row.add(cur.val); if (cur.left != null ) q.add(cur.left); if (cur.right != null ) q.add(cur.right); } f++; if (f % 2 == 0 ) Collections.reverse(row); res.add(row); } return res; } }
使用两个栈,利用先进后出特性来反转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.*;public class Solution { public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) { TreeNode h = pRoot; ArrayList<ArrayList<Integer>> res = new ArrayList <>(); if (h == null ) return res; Stack<TreeNode> s1 = new Stack <TreeNode>(); Stack<TreeNode> s2 = new Stack <TreeNode>(); s1.push(h); while (!s1.isEmpty() || !s2.isEmpty()){ ArrayList<Integer> row = new ArrayList <>(); while (!s1.isEmpty()){ TreeNode cur = s1.pop(); row.add(cur.val); if (cur.left != null ) s2.add(cur.left); if (cur.right != null ) s2.add(cur.right); } if (row.size() != 0 ) res.add(new ArrayList <Integer>(row)); row.clear(); while (!s2.isEmpty()){ TreeNode cur = s2.pop(); row.add(cur.val); if (cur.right != null ) s1.add(cur.right); if (cur.left != null ) s1.add(cur.left); } if (row.size() != 0 ) res.add(new ArrayList <Integer>(row)); row.clear(); } return res; } }
BM28 二叉树的最大深度
二叉树的最大深度_牛客题霸_牛客网https://www.nowcoder.com/practice/8a2b2bf6c19b4f23a9bdb9b233eefa73?tpId=295&tqId=642&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public int maxDepth (TreeNode root) { if (root == null ) return 0 ; Queue<TreeNode> q = new LinkedList <TreeNode>(); int res = 0 ; q.add(root); while (!q.isEmpty()) { int size = q.size(); for (int i = 0 ; i < size; i++) { TreeNode node = q.poll(); if (node.left != null ) q.add(node.left); if (node.right != null ) q.add(node.right); } res++; } return res; } }
BM29 二叉树中和为某一值的路径(一)
二叉树中和为某一值的路径(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/508378c0823c423baa723ce448cbfd0c?tpId=295&tqId=634&sourceUrl=%2Fexam%2Foj%3Fpage%3D1%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AC%2594%25E9%259D%25A2%25E8%25AF%2595%25E7%25AF%2587%26topicId%3D295 2025年8月13日16:38:15 2025年8月13日16:48:21
递归
1 2 3 4 5 6 7 8 9 10 11 import java.util.*;public class Solution { public boolean hasPathSum (TreeNode root, int sum) { if (root == null ) return false ; if (root.left == null && root.right == null && root.val == sum) return true ; return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); } }
使用广搜,Pair记录从头节点到叶子的总值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import java.util.*;public class Solution { class P { TreeNode node = null ; int cursum = 0 ; public P (TreeNode node, int cursum) { this .node = node; this .cursum = cursum; } } public boolean hasPathSum (TreeNode root, int sum) { if (root == null ) return false ; Queue<P> q = new LinkedList <>(); P p = new P (root, root.val); q.add(p); while (!q.isEmpty()) { P cur = q.poll(); if (cur.node.left != null ) { q.add( new P ( cur.node.left, cur.cursum + cur.node.left.val ) ); } if (cur.node.right != null ) { q.add( new P ( cur.node.right, cur.cursum + cur.node.right.val ) ); } if (cur.node.left == null && cur.node.right == null ) { if (sum == cur.cursum) return true ; } } return false ; } }
BM30 二叉搜索树与双向链表
二叉搜索树与双向链表_牛客题霸_牛客网https://www.nowcoder.com/practice/947f6eb80d944a84850b0538bf0ec3a5?tpId=295&tqId=23253&sourceUrl=%2Fexam%2Foj
递归中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { TreeNode head = null ; TreeNode pre = null ; public TreeNode Convert (TreeNode p) { if (p == null ) return null ; Convert(p.left); if (pre == null ) { head = p; pre = p; } else { pre.right = p; p.left = pre; pre = p; } Convert(p.right); return head; } }
非递归中序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;public class Solution { public TreeNode Convert (TreeNode p) { if (p == null ) return null ; Stack<TreeNode> s = new Stack <TreeNode>(); TreeNode head = null ; TreeNode pre = null ; boolean isHead = true ; while (p != null || !s.isEmpty()){ while (p != null ){ s.push(p); p = p.left; } p = s.pop(); if (isHead){ head = p; pre = p; isHead = false ; }else { pre.right = p; p.left = pre; pre = p; } p = p.right; } return head; } }
BM31 对称的二叉树
对称的二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/ff05d44dfdb04e1d83bdbdab320efbcb?tpId=295&tqId=23253&sourceUrl=%2Fexam%2Foj 2025年8月14日14:05:33 2025年8月14日14:22:40
层序遍历 + 回文/对称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.util.*;public class Solution { int INF = 0x3f3f3f ; TreeNode emptyNode = new TreeNode (INF); boolean check (ArrayList<Integer> list) { int n = list.size(); for (int i = 0 ; i < n ; i ++){ if (!list.get(i).equals(list.get(n - 1 - i))) return false ; } return true ; } public boolean isSymmetrical (TreeNode p) { if (p == null ) return true ; Queue<TreeNode> q = new LinkedList <>(); q.offer(p); while (!q.isEmpty()){ int n = q.size(); ArrayList<Integer> row = new ArrayList <>(); for (int i = 0 ; i < n ; i ++){ TreeNode cur = q.poll(); if (!cur.equals(emptyNode)){ q.add(cur.left != null ? cur.left : emptyNode); q.add(cur.right != null ? cur.right : emptyNode); } row.add(cur.val); } if (!check(row)) return false ; } return true ; } }
递归写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { boolean chk (TreeNode p1, TreeNode p2) { if (p1 == null && p2 == null ) return true ; if (p1 == null || p2 == null ) return false ; if (p1.val != p2.val) return false ; return chk(p1.left, p2.right) && chk(p1.right, p2.left); } public boolean isSymmetrical (TreeNode p) { return chk(p, p); } }
BM32 合并二叉树
合并二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/7298353c24cc42e3bd5f0e0bd3d1d759?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public TreeNode mergeTrees (TreeNode t1, TreeNode t2) { if (t1 == null ) return t2; if (t2 == null ) return t1; TreeNode head = new TreeNode (t1.val + t2.val); head.left = mergeTrees(t1.left, t2.left); head.right = mergeTrees(t1.right, t2.right); return head; } }
BM33 二叉树的镜像
二叉树的镜像_牛客题霸_牛客网https://www.nowcoder.com/practice/a9d0ecbacef9410ca97463e4a5c83be7?tpId=295&tqId=1374963&sourceUrl=%2Fexam%2Foj
直接递归
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.*;public class Solution { public TreeNode Mirror (TreeNode p) { if (p == null ) return null ; TreeNode left = Mirror(p.left); TreeNode right = Mirror(p.right); p.left = right; p.right = left; return p; } }
借助辅助空间,栈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public TreeNode Mirror (TreeNode p) { if (p == null ) return null ; Stack<TreeNode> s = new Stack <TreeNode>(); s.push(p); while (!s.isEmpty()) { TreeNode cur = s.pop(); if (cur.left != null ) s.push(cur.left); if (cur.right != null ) s.push(cur.right); TreeNode temp = cur.left; cur.left = cur.right; cur.right = temp; } return p; } }
BM34 判断是不是二叉搜索树
判断是不是二叉搜索树_牛客题霸_牛客网https://www.nowcoder.com/practice/a69242b39baf45dea217815c7dedb52b?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
栈模拟,然后中序遍历是否单调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public boolean isValidBST (TreeNode root) { if (root == null ) return true ; Stack<TreeNode> s = new Stack <TreeNode>(); ArrayList<Integer> list = new ArrayList <Integer>(); TreeNode head = root; while (head != null || !s.isEmpty()) { while (head != null ) { s.push(head); head = head.left; } head = s.pop(); list.add(head.val); head = head.right; } for (int i = 1 ; i < list.size(); i++) { if (list.get(i) <= list.get(i - 1 )) return false ; } return true ; } }
递归
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.*;public class Solution { int pre = Integer.MIN_VALUE; public boolean isValidBST (TreeNode root) { if (root == null ) return true ; if (!isValidBST(root.left)) return false ; if (root.val < pre) return false ; pre = root.val; return isValidBST(root.right); } }
BM35 判断是不是完全二叉树
判断是不是完全二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/8daa4dff9e36409abba2adbe413d6fae?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public boolean isCompleteTree (TreeNode root) { if (root == null ) return true ; Queue<TreeNode> q = new LinkedList <TreeNode>(); q.offer(root); boolean notOk = false ; while (!q.isEmpty()){ TreeNode cur = q.poll(); if (cur == null ) { notOk = true ; continue ; } if (notOk) return false ; q.offer(cur.left); q.offer(cur.right); } return true ; } }
BM36 判断是不是平衡二叉树
判断是不是平衡二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { boolean isOk = true ; public int depth (TreeNode p) { if (p == null ){ return 0 ; } int l = depth(p.left); int r = depth(p.right); if (Math.abs(l - r) > 1 ){ isOk = false ; } return Math.max(l, r) + 1 ; } public boolean IsBalanced_Solution (TreeNode pRoot) { int d = depth(pRoot); return isOk; } }
方法一 剪枝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { boolean isOk = true ; public int depth (TreeNode p) { if (p == null ){ return 0 ; } int l = depth(p.left); if (l == -1 ) return -1 ; int r = depth(p.right); if (r == -1 ) return -1 ; if (Math.abs(l - r) > 1 ){ isOk = false ; return -1 ; } return Math.max(l, r) + 1 ; } public boolean IsBalanced_Solution (TreeNode pRoot) { int d = depth(pRoot); return isOk; } }
BM37 二叉搜索树的最近公共祖先
二叉搜索树的最近公共祖先_牛客题霸_牛客网https://www.nowcoder.com/practice/d9820119321945f588ed6a26f0a6991f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
遍历两个节点的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;public class Solution { ArrayList<Integer> getPath (TreeNode r, int n) { ArrayList<Integer> res = new ArrayList <Integer>(); TreeNode p = r; while (p.val != n){ res.add(p.val); if (n < p.val){ p = p.left; }else { p = p.right; } } res.add(p.val); return res; } public int lowestCommonAncestor (TreeNode r, int p, int q) { ArrayList<Integer> ppath = getPath(r,p); ArrayList<Integer> qpath = getPath(r,q); int ans = 0 ; for (int i = 0 ; i < ppath.size() && i < qpath.size(); i ++){ int x = ppath.get(i); int y = qpath.get(i); if (x == y) ans = ppath.get(i); else break ; } return ans; } }
用一个set存 遍历到最后一个一样的节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public int lowestCommonAncestor (TreeNode r, int p, int q) { Set<Integer> s = new HashSet <Integer>(); TreeNode cur = r; while (cur.val != p){ s.add(cur.val); if (cur.val > p) cur = cur.left; else cur = cur.right; } s.add(cur.val); cur = r; int res = -1 ; while (cur.val != q){ if (s.contains(cur.val)) res = cur.val; if (cur.val > q) cur = cur.left; else cur = cur.right; } return res == -1 ? q : res; } }
BM38 在二叉树中找到两个节点的最近公共祖先
在二叉树中找到两个节点的最近公共祖先_牛客题霸_牛客网https://www.nowcoder.com/practice/e0cc33a83afe4530bcec46eba3325116?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
dfs + 路径比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util.*;public class Solution { boolean ok = false ; void depth (TreeNode p,int t,ArrayList<Integer> cur) { if (p == null || ok) return ; cur.add(p.val); if (p.val == t){ ok = true ; return ; } depth(p.left,t,cur); depth(p.right,t,cur); if (ok) return ; cur.remove(cur.size() - 1 ); } public int lowestCommonAncestor (TreeNode root, int o1, int o2) { ArrayList<Integer> l1 = new ArrayList <Integer>(); ArrayList<Integer> l2 = new ArrayList <Integer>(); ok = false ; depth(root,o1,l1); ok = false ; depth(root,o2,l2); int res = 0 ; for (int i = 0 ; i < l1.size() && i < l2.size(); i ++){ if (l1.get(i).equals(l2.get(i))) res = l1.get(i); else break ; } return res; } }
递归
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.util.*;public class Solution { public int lowestCommonAncestor (TreeNode r, int o1, int o2) { if (r == null ) return -1 ; if (r.val == o1 || r.val == o2) return r.val; int lf = lowestCommonAncestor(r.left, o1, o2); int rh = lowestCommonAncestor(r.right, o1, o2); if (lf == -1 ) return rh; if (rh == -1 ) return lf; return r.val; } }
BM39 序列化二叉树
序列化二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/cf7e25aa97c04cc1a68c8f040e71fb84?tpId=295&tqId=23455&sourceUrl=%2Fexam%2Foj
广搜遍历 + StringBuilder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 import java.util.*;public class Solution { int INF = Integer.MAX_VALUE; TreeNode emptyNode = new TreeNode (INF); String Serialize (TreeNode r) { if (r == null ) return "" ; StringBuilder sb = new StringBuilder (); Deque<TreeNode> dq = new ArrayDeque <>(); dq.addLast(r); while (!dq.isEmpty()) { TreeNode cur = dq.pollFirst(); sb.append(cur.val + "_" ); if (!cur.equals(emptyNode)) { dq.addLast(cur.left != null ? cur.left : emptyNode); dq.addLast(cur.right != null ? cur.right : emptyNode); } } return sb.toString(); } TreeNode Deserialize (String str) { if (str.equals("" )) return null ; String[] s = str.split("_" ); int n = s.length; TreeNode p = new TreeNode (Integer.parseInt(s[0 ])); Deque<TreeNode> dq = new ArrayDeque <TreeNode>(); dq.addLast(p); for (int i = 1 ; i < n - 1 ; i += 2 ) { TreeNode cur = dq.pollFirst(); int l = Integer.parseInt(s[i]), r = Integer.parseInt(s[i + 1 ]); if (l != INF) { cur.left = new TreeNode (l); dq.addLast(cur.left); } if (r != INF) { cur.right = new TreeNode (r); dq.addLast(cur.right); } } return p; } }
递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import java.util.*;public class Solution { static int idx = 0 ; void SerializeFuction (TreeNode p, StringBuilder sb) { if (p == null ) { sb.append('#' ); return ; } sb.append(p.val).append("_" ); SerializeFuction(p.left, sb); SerializeFuction(p.right, sb); } String Serialize (TreeNode r) { if (r == null ) return "#" ; StringBuilder res = new StringBuilder (); SerializeFuction(r, res); return res.toString(); } TreeNode DeserializeFuction (String str) { if (str.charAt(idx) == '#' ) { idx++; return null ; } int val = 0 ; while (str.charAt(idx) != '_' && idx != str.length()) { val = val * 10 + (str.charAt(idx) - '0' ); idx++; } TreeNode p = new TreeNode (val); if (idx == str.length()) return p; else idx++; p.left = DeserializeFuction(str); p.right = DeserializeFuction(str); return p; } TreeNode Deserialize (String str) { if (str.equals("#" )) return null ; idx = 0 ; TreeNode res = DeserializeFuction(str); return res; } }
BM40 重建二叉树
重建二叉树_牛客题霸_牛客网https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public TreeNode reConstructBinaryTree (int [] pre, int [] vin) { int n = pre.length; int m = vin.length; if (n == 0 || m == 0 ) return null ; TreeNode r = new TreeNode (pre[0 ]); for (int i = 0 ; i < vin.length; i++) { if (pre[0 ] == vin[i]) { r.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1 , i + 1 ), Arrays.copyOfRange(vin, 0 , i)); r.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1 , n), Arrays.copyOfRange(vin, i + 1 , m)); break ; } } return r; } }
栈遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.util.*;public class Solution { public TreeNode reConstructBinaryTree (int [] pre, int [] vin) { int n = pre.length; int m = pre.length; if (n == 0 || m == 0 ) return null ; Stack<TreeNode> s = new Stack <TreeNode>(); TreeNode r = new TreeNode (pre[0 ]); TreeNode cur = r; for (int i = 1 , j = 0 ; i < n; i++) { if (cur.val != vin[j]) { cur.left = new TreeNode (pre[i]); s.push(cur); cur = cur.left; } else { j++; while (!s.isEmpty() && s.peek().val == vin[j]) { cur = s.pop(); j++; } cur.right = new TreeNode (pre[i]); cur = cur.right; } } return r; } }
BM41 输出二叉树的右视图
输出二叉树的右视图_牛客题霸_牛客网https://www.nowcoder.com/practice/c9480213597e45f4807880c763ddd5f0?tpId=295&tqId=1073834&sourceUrl=%2Fexam%2Foj
递归建树 , 一个哈希表维护最深节点,两个栈分别维护节点和深度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import java.util.*;public class Solution { TreeNode buildTree (int [] pre, int [] in, int preStart, int preEnd, int inStart, int inEnd) { if (preStart > preEnd || inStart > inEnd) return null ; TreeNode p = new TreeNode (pre[preStart]); int idx = inStart; while (idx <= inEnd && in[idx] != pre[preStart]) idx++; int leftSize = idx - inStart; p.left = buildTree(pre, in, preStart + 1 , preStart + leftSize, inStart, idx - 1 ); p.right = buildTree(pre, in, preStart + leftSize + 1 , preEnd, idx + 1 , inEnd); return p; } ArrayList<Integer> rightSideView (TreeNode r) { ArrayList<Integer> res = new ArrayList <>(); if (r == null ) return res; Queue<TreeNode> q = new LinkedList <>(); q.add(r); while (!q.isEmpty()) { int size = q.size(); for (int i = 0 ; i < size; i++) { TreeNode cur = q.poll(); if (i == size - 1 ) { res.add(cur.val); } if (cur.left != null ) q.add(cur.left); if (cur.right != null ) q.add(cur.right); } } return res; } public int [] solve(int [] pre, int [] in) { int n = pre.length; int m = in.length; if (m == 0 || n == 0 ) return new int [0 ]; TreeNode r = buildTree(pre, in, 0 , n - 1 , 0 , m - 1 ); ArrayList<Integer> tmp = rightSideView(r); int [] res = new int [tmp.size()]; for (int i = 0 ; i < tmp.size(); i++) res[i] = tmp.get(i); return res; } }
库函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import java.util.*;public class Solution { TreeNode buildTree (int [] pre, int l1, int r1, int [] in, int l2, int r2) { if (l1 > r1 || l2 > r2) return null ; TreeNode p = new TreeNode (pre[l1]); int idx = 0 ; for (int i = l2; i <= r2; i++) { if (in[i] == pre[l1]) { idx = i; break ; } } int lsize = idx - l2; int rsize = r2 - idx; p.left = buildTree(pre, l1 + 1 , l1 + lsize, in, l2, l2 + lsize - 1 ); p.right = buildTree(pre, r1 - rsize + 1 , r1, in, idx + 1 , r2); return p; } ArrayList<Integer> rightSideView (TreeNode r) { Map<Integer, Integer> mp = new HashMap <Integer, Integer>(); int maxdepth = -1 ; Stack<TreeNode> s1 = new Stack <TreeNode>(); Stack<Integer> s2 = new Stack <Integer>(); s1.push(r); s2.push(0 ); while (!s1.isEmpty()) { TreeNode cur = s1.pop(); int curdepth = s2.pop(); if (cur != null ) { maxdepth = Math.max(maxdepth, curdepth); if (mp.get(curdepth) == null ) { mp.put(curdepth, cur.val); } s1.push(cur.left); s1.push(cur.right); s2.push(curdepth + 1 ); s2.push(curdepth + 1 ); } } ArrayList<Integer> res = new ArrayList <>(); for (int i = 0 ; i <= maxdepth; i++) { res.add(mp.get(i)); } return res; } public int [] solve(int [] pre, int [] in) { int n = pre.length; int m = in.length; if (m == 0 || n == 0 ) return new int [0 ]; TreeNode r = buildTree(pre, 0 , n - 1 , in, 0 , m - 1 ); ArrayList<Integer> tmp = rightSideView(r); int [] res = new int [tmp.size()]; for (int i = 0 ; i < tmp.size(); i++) res[i] = tmp.get(i); return res; } }
堆/栈/队列
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM42
用两个栈实现队列
使用两个栈模拟队列的先进先出特性,一个栈用于存储元素,另一个栈用于反转元素顺序
O(1)
O(n)
代码逻辑清晰,通过两个栈的交互实现队列功能
🔗直达
BM43
包含min函数的栈
使用两个栈,一个存储所有元素,另一个存储当前最小值,通过辅助栈实现O(1)时间复杂度的min函数
O(1)
O(n)
使用辅助栈优化min函数的实现,代码简洁高效
🔗直达
BM44
有效括号序列
使用栈存储预期的闭合字符,遍历字符串时检查括号匹配情况
O(n)
O(n)
利用栈的特性高效判断括号匹配,代码易于理解
🔗直达
BM45
滑动窗口的最大值
使用双端队列维护窗口内的最大值索引,通过队列的特性实现O(n)时间复杂度
O(n)
O(n)
利用双端队列优化滑动窗口的最大值查找,代码逻辑清晰
🔗直达
BM46
最小的K个数
使用大根堆或小根堆筛选最小的K个数,通过堆的特性优化查找效率
O(nlogk)
O(k)
提供了多种解法,包括排序、大根堆和小根堆,代码可读性强
🔗直达
BM47
寻找第K大
使用大根堆或排序找到第K大的元素,通过堆的特性优化查找效率
O(nlogn)
O(1)
提供了多种解法,包括大根堆、排序和模拟快排,代码逻辑清晰
🔗直达
BM48
数据流中的中位数
使用两个堆(最大堆和最小堆)动态维护中位数,通过堆的特性实现高效查找
O(nlogn)
O(n)
利用两个堆的特性优化中位数的查找,代码结构合理
🔗直达
BM49
表达式求值
使用递归和栈解析表达式,支持加减乘和括号
O(n)
O(n)
使用递归和栈实现表达式求值,代码逻辑清晰,易于扩展
🔗直达
✅ 建议复习顺序(由易到难):
BM42 → BM44 → BM43 → BM45 → BM46 → BM47 → BM48 → BM49
BM42 用两个栈实现队列
用两个栈实现队列_牛客题霸_牛客网https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=295&tqId=23281&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;import java.util.Stack;public class Solution { Stack<Integer> stack1 = new Stack <Integer>(); Stack<Integer> stack2 = new Stack <Integer>(); public void push (int node) { stack1.push(node); } public int pop () { int ans = 0 ; while (!stack1.isEmpty()) {stack2.push(stack1.pop());} ans = stack2.pop(); while (!stack2.isEmpty()) {stack1.push(stack2.pop());} return ans; } }
BM43 包含min函数的栈
包含min函数的栈_牛客题霸_牛客网https://www.nowcoder.com/practice/4c776177d2c04c2494f2555c9fcc1e49?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;import java.util.Stack;public class Solution { Stack<Integer> s1 = new Stack <Integer>(); Stack<Integer> s2 = new Stack <Integer>(); public void push (int node) { s1.push(node); if (s2.isEmpty() || s2.peek() > node) { s2.push(node); } else { s2.push(s2.peek()); } } public void pop () { s1.pop(); s2.pop(); } public int top () { return s1.peek(); } public int min () { return s2.peek(); } }
BM44 有效括号序列
有效括号序列_牛客题霸_牛客网https://www.nowcoder.com/practice/37548e94a270412c8b9fb85643c8ccc2?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public boolean isValid (String s) { Stack<Character> st = new Stack <Character>(); for (int i = 0 ; i < s.length(); i++) { if (s.charAt(i) == '(' ) st.push(')' ); else if (s.charAt(i) == '[' ) st.push(']' ); else if (s.charAt(i) == '{' ) st.push('}' ); else if (st.isEmpty() || st.pop() != s.charAt(i)) return false ; } return st.isEmpty(); } }
BM45 滑动窗口的最大值
滑动窗口的最大值_牛客题霸_牛客网https://www.nowcoder.com/practice/1624bc35a45c42c0bc17d17fa0cba788?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page 2025年8月18日20:05:05 2025年8月18日20:39:57 (- 8:20)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Solution { public ArrayList<Integer> maxInWindows (int [] num, int size) { Deque<Integer> dq = new ArrayDeque <>(); ArrayList<Integer> ans = new ArrayList <>(); int n = num.length; if (num.length == 0 || size < 1 || size > num.length) return ans; for (int i = 0 ; i < n; i++) { while (!dq.isEmpty() && num[dq.peekLast()] < num[i]) { dq.pollLast(); } dq.addLast(i); if (dq.peekFirst() + size <= i) { dq.pollFirst(); } if (i + 1 >= size) { ans.add(num[dq.peekFirst()]); } } return ans; } }
BM46 最小的K个数
最小的K个数_牛客题霸_牛客网https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page 2025年8月18日20:50:45 2025年8月18日20:58:33
排序
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.*;public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution (int [] input, int k) { int [] ans = Arrays.copyOfRange(input, 0 , input.length); Arrays.sort(ans); ArrayList<Integer> ans2 = new ArrayList <Integer>(); for (int i = 0 ; i < k; i++) ans2.add(ans[i]); return ans2; } }
大根堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution (int [] in, int k) { ArrayList<Integer> ans = new ArrayList <Integer>(); int n = in.length; if (k == 0 || n == 0 ) return ans; PriorityQueue<Integer> q = new PriorityQueue <>((o1, o2) -> o2 - o1); for (int i = 0 ; i < k; i++) { q.offer(in[i]); } for (int i = k; i < n; i++) { if (q.peek() > in[i]) { q.poll(); q.offer(in[i]); } } for (int i = 0 ; i < k; i++) { ans.add(q.poll()); } return ans; } }
小根堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public ArrayList<Integer> GetLeastNumbers_Solution (int [] in, int k) { ArrayList<Integer> ans = new ArrayList <Integer>(); int n = in.length; if (k == 0 || n == 0 ) return ans; PriorityQueue<Integer> q = new PriorityQueue <>((o1, o2) -> o1 - o2); for (int i = 0 ; i < n; i++) q.add(in[i]); for (int i = 0 ; i < k; i++) ans.add(q.poll()); return ans; } }
BM47 寻找第K大
寻找第K大_牛客题霸_牛客网https://www.nowcoder.com/practice/e016ad9b7f0b45048c58a9f27ba618bf?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
大根堆
1 2 3 4 5 6 7 8 9 10 import java.util.*;public class Solution { public int findKth (int [] a, int n, int K) { PriorityQueue<Integer> q = new PriorityQueue <>((o1, o2) -> o2 - o1); for (int i = 0 ; i < n; i++) q.add(a[i]); for (int i = 0 ; i < K - 1 ; i++) q.poll(); return q.poll(); } }
排序
1 2 3 4 5 6 7 8 import java.util.*;public class Solution { public int findKth (int [] a, int n, int K) { Arrays.sort(a); return a[n - K]; } }
模拟快排 归并找到倒第K个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 import java.util.*;public class Solution { Random r = new Random (); void swap (int arr[], int a, int b) { int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } int partition (int [] a, int low, int high, int k) { int x = Math.abs(r.nextInt()) % (high - low + 1 ) + low; swap(a, low, x); int v = a[low]; int i = low + 1 ; int j = high; while (true ) { while (j >= low + 1 && a[j] < v) j--; while (i <= high && a[i] > v) i++; if (i > j) break ; swap(a, i, j); i++; j--; } swap(a, low, j); if (j + 1 == k) return a[j]; else if (j + 1 < k) return partition(a, j + 1 , high, k); else return partition(a, low, j - 1 , k); } public int findKth (int [] a, int n, int K) { return partition(a, 0 , n - 1 , K); } }
BM48 数据流中的中位数
数据流中的中位数_牛客题霸_牛客网https://www.nowcoder.com/practice/9be0172896bd43948f8a32fb954e1be1?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page 2025年8月18日21:28:49 2025年8月18日22:09:09
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { private PriorityQueue<Integer> midr = new PriorityQueue <>(); private PriorityQueue<Integer> midl = new PriorityQueue <>(Collections.reverseOrder()); public void Insert (Integer num) { midl.offer(num); midr.offer(midl.poll()); if (midl.size() < midr.size()) midl.offer(midr.poll()); } public Double GetMedian () { if (midl.size() > midr.size()) return (double ) midl.peek(); else return (double ) (midl.peek() + midr.peek()) / 2 ; } }
BM49 表达式求值
表达式求值_牛客题霸_牛客网https://www.nowcoder.com/practice/c215ba61c8b1443b996351df929dc4d4?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj%3FquestionJobId%3D10%26subTabName%3Donline_coding_page
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import java.util.*;public class Solution { ArrayList<Integer> func (String s, int idx) { Stack<Integer> st = new Stack <Integer>(); int num = 0 ; char op = '+' ; int i; for (i = idx; i < s.length(); i++) { if (s.charAt(i) >= '0' && s.charAt(i) <= '9' ) { num = num * 10 + (s.charAt(i) - '0' ); if (i != s.length() - 1 ) continue ; } if (s.charAt(i) == '(' ) { ArrayList<Integer> res = func(s, i + 1 ); num = res.get(0 ); i = res.get(1 ); if (i != s.length() - 1 ) continue ; } switch (op) { case '+' : st.push(num); break ; case '-' : st.push(-num); break ; case '*' : int temp = st.pop(); st.push(temp * num); break ; } num = 0 ; if (s.charAt(i) == ')' ) { break ; } else { op = s.charAt(i); } } int sum = 0 ; while (!st.isEmpty()) { sum += st.pop(); } ArrayList<Integer> temp = new ArrayList <Integer>(); temp.add(sum); temp.add(i); return temp; } public int solve (String s) { ArrayList<Integer> ans = func(s, 0 ); return ans.get(0 ); } }
哈希
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM50
两数之和
使用哈希表存储目标值与当前值的差值及其索引,快速查找
O(n)
O(n)
使用哈希表优化查找过程,逻辑简洁
🔗 直达
BM51
数组中出现次数超过一半的数字
使用哈希表统计每个数字的出现次数
O(n)
O(n)
使用哈希表快速统计次数,逻辑清晰
🔗 直达
BM52
数组中只出现一次的两个数字
使用哈希表统计每个数字的出现次数,找出只出现一次的数字
O(n)
O(n)
使用哈希表优化查找过程,逻辑简洁
🔗 直达
BM53
缺失的第一个正整数
使用集合存储数组中的数字,查找最小未出现的正整数
O(n)
O(n)
使用集合优化查找过程,逻辑简洁
🔗 直达
BM54
三数之和
排序后使用双指针查找满足条件的三元组
O(n^2)
O(n)
使用排序和双指针优化查找过程,逻辑清晰
🔗 直达
✅ 建议复习顺序(由易到难):
BM50 → BM51 → BM52 → BM53 → BM54
BM50 两数之和
两数之和_牛客题霸_牛客网https://www.nowcoder.com/practice/20ef0972485e41019e39543e8e895b7f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public int [] twoSum(int [] numbers, int target) { HashMap<Integer, Integer> mp = new HashMap <>(); for (int i = 0 ; i < numbers.length; i++) { if (mp.containsKey(numbers[i])) { int x = mp.get(numbers[i]); return new int []{x + 1 , i + 1 }; } mp.put(target - numbers[i], i); } return null ; } }
BM51 数组中出现次数超过一半的数字
数组中出现次数超过一半的数字_牛客题霸_牛客网https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年8月19日16:55:36 2025年8月19日16:57:20
1 2 3 4 5 6 7 8 9 10 11 12 import java.util.*;public class Solution { public int MoreThanHalfNum_Solution (int [] numbers) { Map<Integer, Integer> mp = new HashMap <>(); for (int i : numbers) { mp.merge(i, 1 , Integer::sum); if (mp.get(i) * 2 > numbers.length) return i; } return 0 ; } }
BM52 数组中只出现一次的两个数字
数组中只出现一次的两个数字_牛客题霸_牛客网https://www.nowcoder.com/practice/389fc1c3d3be4479a154f63f495abff8?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年8月19日16:57:47 2025年8月19日17:06:07
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Solution { public int [] FindNumsAppearOnce(int [] nums) { Map<Integer, Integer> mp = new HashMap <>(); for (int i : nums) { mp.merge(i, 1 , Integer::sum); } ArrayList<Integer> ans = new ArrayList <Integer>(); for (Map.Entry<Integer, Integer> m : mp.entrySet()) { System.out.print(m.getKey() + " " + m.getValue()); if (m.getValue() == 1 ) ans.add(m.getKey()); } int [] res = new int [2 ]; for (int i = 0 ; i < 2 ; i++) res[i] = ans.get(i); return res; } }
BM53 缺失的第一个正整数
缺失的第一个正整数_牛客题霸_牛客网https://www.nowcoder.com/practice/50ec6a5b0e4e45348544348278cdcee5?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年8月19日17:06:49 2025年8月19日17:08:24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public int minNumberDisappeared (int [] nums) { Set<Integer> s = new HashSet <>(); for (int i : nums) { s.add(i); } int ans = 1 ; while (s.contains(ans)) { ans++; } return ans; } }
BM54 三数之和
三数之和_牛客题霸_牛客网https://www.nowcoder.com/practice/345e2ed5f81d4017bbb8cc6055b0b711?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年8月19日17:09:15 2025年8月19日17:44:12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.*;public class Solution { public ArrayList<ArrayList<Integer>> threeSum (int [] num) { int n = num.length; ArrayList<ArrayList<Integer>> ans = new ArrayList <>(); if (n < 3 ) return ans; Arrays.sort(num); for (int i = 0 ; i < num.length - 2 ; i++) { int j = i + 1 ; int k = num.length - 1 ; int t = -num[i]; while (j < k) { if (num[j] + num[k] > t) k--; else if (num[j] + num[k] < t) j++; else { ArrayList<Integer> l = new ArrayList <>(Arrays.asList(num[i], num[j], num[k])); ans.add(l); while (j + 1 < k && num[j + 1 ] == num[j]) j++; while (k - 1 > j && num[k - 1 ] == num[k]) k--; j++; k--; } } while (i + 1 < num.length - 2 && num[i + 1 ] == num[i]) i++; } return ans; } }
递归/回溯
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM55
没有重复项数字的全排列
使用回溯法生成所有排列
O(n!)
O(n)
使用回溯法生成所有排列,逻辑清晰
🔗 直达
BM56
有重复项数字的全排列
使用回溯法生成所有排列,并通过排序和剪枝去重
O(n!)
O(n)
使用排序和剪枝去重,避免重复排列
🔗 直达
BM57
岛屿数量
使用深度优先搜索(DFS)或广度优先搜索(BFS)标记岛屿
O(n×m)
O(n×m)
使用DFS或BFS标记岛屿,逻辑清晰
🔗 直达
BM58
字符串的排列
使用回溯法生成所有排列,并通过排序和剪枝去重
O(n!)
O(n)
使用排序和剪枝去重,避免重复排列
🔗 直达
BM59
N皇后问题
使用回溯法放置皇后,并通过判断函数检查冲突
O(n!)
O(n)
使用回溯法放置皇后,逻辑清晰
🔗 直达
BM60
括号生成
使用回溯法生成所有合法括号组合
O(2^n)
O(n)
使用回溯法生成所有合法括号组合,逻辑清晰
🔗 直达
BM61
矩阵最长递增路径
使用深度优先搜索(DFS)和动态规划(DP)计算最长递增路径
O(n×m)
O(n×m)
使用DFS和DP计算最长递增路径,逻辑清晰
🔗 直达
✅ 建议复习顺序(由易到难):
BM55 → BM56 → BM57 → BM60 → BM58→ BM61→ BM59
BM55 没有重复项数字的全排列
没有重复项数字的全排列_牛客题霸_牛客网https://www.nowcoder.com/practice/4bcf3081067a4d028f95acee3ddcd2b1?tpId=295&tqId=701&sourceUrl=%2Fexam%2Foj
搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import java.util.*;public class Solution { void backTrack (int [] num, LinkedList<Integer> cur, ArrayList<ArrayList<Integer>> res) { if (cur.size() == num.length) { res.add(new ArrayList <>(cur)); return ; } for (int i = 0 ; i < num.length; i++) { if (cur.contains(num[i])) { continue ; } cur.add(num[i]); backTrack(num, cur, res); cur.removeLast(); } } public ArrayList<ArrayList<Integer>> permute (int [] num) { ArrayList<ArrayList<Integer>> res = new ArrayList <ArrayList<Integer>>(); LinkedList<Integer> cur = new LinkedList <>(); backTrack(num, cur, res); return res; } }
使用记忆数组标记
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;public class Solution { void backTrack (int [] num, LinkedList<Integer> cur, ArrayList<ArrayList<Integer>> res, boolean [] vis) { if (cur.size() == num.length) { res.add(new ArrayList <>(cur)); return ; } for (int i = 0 ; i < num.length; i++) { if (vis[i]) { continue ; } cur.add(num[i]); vis[i] = true ; backTrack(num, cur, res, vis); cur.removeLast(); vis[i] = false ; } } public ArrayList<ArrayList<Integer>> permute (int [] num) { ArrayList<ArrayList<Integer>> res = new ArrayList <ArrayList<Integer>>(); LinkedList<Integer> cur = new LinkedList <>(); boolean [] vis = new boolean [num.length]; backTrack(num, cur, res, vis); return res; } }
BM56 有重复项数字的全排列
有重复项数字的全排列_牛客题霸_牛客网https://www.nowcoder.com/practice/a43a2b986ef34843ac4fdd9159b69863?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.*;public class Solution { public void recursion (ArrayList<ArrayList<Integer>> res, int [] num, ArrayList<Integer> temp, Boolean[] vis) { if (temp.size() == num.length) { res.add(new ArrayList <Integer>(temp)); return ; } for (int i = 0 ; i < num.length; i++) { if (vis[i]) continue ; if (i > 0 && num[i - 1 ] == num[i] && !vis[i - 1 ]) continue ; vis[i] = true ; temp.add(num[i]); recursion(res, num, temp, vis); vis[i] = false ; temp.remove(temp.size() - 1 ); } } public ArrayList<ArrayList<Integer>> permuteUnique (int [] num) { Arrays.sort(num); Boolean[] vis = new Boolean [num.length]; Arrays.fill(vis, false ); ArrayList<ArrayList<Integer>> res = new ArrayList <ArrayList<Integer>>(); ArrayList<Integer> temp = new ArrayList <Integer>(); recursion(res, num, temp, vis); return res; } }
BM57 岛屿数量
岛屿数量_牛客题霸_牛客网https://www.nowcoder.com/practice/0c9664d1554e466aa107d899418e814e?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.util.*;public class Solution { int [] dx = {1 , -1 , 0 , 0 }; int [] dy = {0 , 0 , 1 , -1 }; void dfs (char [][] grid, int i, int j) { int n = grid.length; int m = grid[0 ].length; grid[i][j] = '0' ; for (int k = 0 ; k < 4 ; k++) { int ti = i + dx[k]; int tj = j + dy[k]; if (ti >= 0 && ti < n && tj >= 0 && tj < m && grid[ti][tj] == '1' ) { dfs(grid, ti, tj); } } } public int solve (char [][] grid) { int n = grid.length; if (n == 0 ) return 0 ; int m = grid[0 ].length; int cnt = 0 ; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (grid[i][j] == '1' ) { cnt++; dfs(grid, i, j); } } } return cnt; } }
BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import java.util.*;public class Solution { int dx[] = {0 , 0 , 1 , -1 }; int dy[] = {1 , -1 , 0 , 0 }; int n = 0 ; int m = 0 ; int cnt = 0 ; class Node { int i; int j; public Node (int i, int j) { this .i = i; this .j = j; } } void bfs (char [][] grid, int i, int j) { Queue<Node> q = new LinkedList <>(); q.add(new Node (i, j)); while (!q.isEmpty()) { Node t = q.poll(); grid[t.i][t.j] = '0' ; for (int k = 0 ; k < 4 ; k++) { int ti = dx[k] + t.i; int tj = dy[k] + t.j; if (ti >= 0 && tj >= 0 && ti < n && tj < m && grid[ti][tj] == '1' ) { q.add(new Node (ti, tj)); } } } cnt++; } public int solve (char [][] grid) { this .n = grid.length; if (n == 0 ) return 0 ; this .m = grid[0 ].length; this .cnt = 0 ; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (grid[i][j] == '1' ) { bfs(grid, i, j); } } } return cnt; } }
BM58 字符串的排列
字符串的排列_牛客题霸_牛客网https://www.nowcoder.com/practice/fe6b651b66ae47d7acce78ffdd9a96c7?tpId=295&tqId=23291&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.*;public class Solution { public void recursion (ArrayList<String> res, char [] str, StringBuffer temp, boolean [] vis) { if (temp.length() == str.length) { res.add(new String (temp)); return ; } for (int i = 0 ; i < str.length; i++) { if (vis[i]) continue ; if (i > 0 && str[i - 1 ] == str[i] && !vis[i - 1 ]) continue ; vis[i] = true ; temp.append(str[i]); recursion(res, str, temp, vis); vis[i] = false ; temp.deleteCharAt(temp.length() - 1 ); } } public ArrayList<String> Permutation (String str) { ArrayList<String> res = new ArrayList <String>(); if (str == null || str.length() == 0 ) return res; char [] charStr = str.toCharArray(); Arrays.sort(charStr); boolean [] vis = new boolean [str.length()]; Arrays.fill(vis, false ); StringBuffer temp = new StringBuffer (); recursion(res, charStr, temp, vis); return res; } }
BM59 N皇后问题
N皇后问题_牛客题霸_牛客网https://www.nowcoder.com/practice/c76408782512486d91eea181107293b6?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
BF 递归 +判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { private int res; public boolean isValid (int [] pos, int row, int col) { for (int i = 0 ; i < row; i++) { if (col == pos[i] || Math.abs(row - i) == Math.abs(col - pos[i])) { return false ; } } return true ; } public void recursion (int n, int row, int [] pos) { if (row == n) { res++; return ; } for (int i = 0 ; i < n; i++) { if (isValid(pos, row, i)) { pos[row] = i; recursion(n, row + 1 , pos); } } } public int Nqueen (int n) { res = 0 ; int [] pos = new int [n]; Arrays.fill(pos, 0 ); recursion(n, 0 , pos); return res; } }
使用哈希表维护
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import java.util.*;public class Solution { Set<Integer> col = new HashSet <Integer>(); Set<Integer> posSlant = new HashSet <Integer>(); Set<Integer> conSlant = new HashSet <Integer>(); int result = 0 ; public int Nqueen (int n) { recursion(0 , n); return result; } private void recursion (int i, int n) { if (i == n) { result++; return ; } for (int j = 0 ; j < n; j++) { if (col.contains(j) || posSlant.contains(i - j) || conSlant.contains(i + j)) { continue ; } col.add(j); posSlant.add(i - j); conSlant.add(i + j); recursion(i + 1 , n); col.remove(j); posSlant.remove(i - j); conSlant.remove(i + j); } } }
位运算优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Solution { int res; public void backtrack (int i, int col, int pos, int neg, int n) { if (i == n) { res++; return ; } int pre = ~(col | pos | neg) & ((1 << n) - 1 ); while (pre > 0 ) { int cur = pre & (-pre); backtrack(i + 1 , col | cur, (pos | cur) >> 1 , (neg | cur) << 1 , n); pre &= pre - 1 ; } } public int Nqueen (int n) { res = 0 ; backtrack(0 , 0 , 0 , 0 , n); return res; } }
BM60 括号生成
括号生成_牛客题霸_牛客网https://www.nowcoder.com/practice/c9addb265cdf4cdd92c092c655d164ca?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public void recursion (int left, int right, String temp, ArrayList<String> res, int n) { if (left == n && right == n) { res.add(temp); return ; } if (left < n) { recursion(left + 1 , right, temp + "(" , res, n); } if (right < n && left > right) { recursion(left, right + 1 , temp + ")" , res, n); } } public ArrayList<String> generateParenthesis (int n) { ArrayList<String> res = new ArrayList <String>(); recursion(0 , 0 , "" , res, n); return res; } }
BM61 矩阵最长递增路径
矩阵最长递增路径_牛客题霸_牛客网https://www.nowcoder.com/practice/7a71a88cdf294ce6bdf54c899be967a2?tpId=295&tqId=1076860&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import java.util.*;public class Solution { int [] dx = {0 , 0 , 1 , -1 }; int [] dy = {1 , -1 , 0 , 0 }; int n, m; int dfs (int [][] matrix, int [][] dp, int i, int j) { if (dp[i][j] != 0 ) return dp[i][j]; dp[i][j]++; for (int k = 0 ; k < 4 ; k++) { int ti = i + dx[k]; int tj = j + dy[k]; if (ti >= 0 && ti < n && tj >= 0 && tj < m && matrix[ti][tj] > matrix[i][j]) { dp[i][j] = Math.max(dp[i][j], dfs(matrix, dp, ti, tj) + 1 ); } } return dp[i][j]; } public int solve (int [][] matrix) { int ans = 0 ; this .n = matrix.length; this .m = matrix[0 ].length; if (n == 0 || m == 0 ) return ans; int [][] dp = new int [n][m]; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { ans = Math.max(ans, dfs(matrix, dp, i, j)); } } return ans; } }
动态规划
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM62
斐波那契数列
动态规划(迭代) / 递归
O(n) / O(2ⁿ)
O(1) / O(n)
迭代版空间 O(1) 优化
🔗 直达
BM63
跳台阶
DP:前两项和
O(n)
O(1)
与斐波那契同模型
🔗 直达
BM64
最小花费爬楼梯
DP:min(前两项花费+成本)
O(n)
O(1)
边界 dp[0]=dp[1]=0 技巧
🔗 直达
BM65
最长公共子序列
二维 DP + 回溯构造子序列
O(n·m)
O(n·m)
方向矩阵 b[][] 回溯输出 LCS
🔗 直达
BM66
最长公共子串
二维 DP + 记录 max 长度位置
O(n·m)
O(n·m)
子串必须连续
🔗 直达
BM67
不同路径的数目(一)
DP 累加 / 组合数 C(m+n-2,n-1)
O(n·m)
O(min(n,m))
组合数写法更简洁
🔗 直达
BM68
矩阵的最小路径和
二维 DP:min(上,左)+当前值
O(n·m)
O(n·m)
从左至右、从上至下
🔗 直达
BM69
数字翻译字符串
线性 DP:单双数字解码
O(n)
O(1)
用于存储每个位置的解码方法数
🔗 直达
BM70
兑换零钱(一)
完全背包求最小硬币数
O(n·aim)
O(aim)
INF=0x3f3f3f3f 初始化技巧
🔗 直达
BM71
最长上升子序列
线性 DP + 贪心优化
O(n²)
O(n)
初始化动态规划数组,每个位置的初始值为 1,因为每个元素自身可以看作长度为 1 的递增子序列
🔗 直达
BM72
连续子数组最大和
Kadane:max(前和+当前, 当前)
O(n)
O(1)
经典最大子段和
🔗 直达
BM73
最长回文子串
中心扩展 / Manacher
O(n²)
O(1)
奇偶中心双指针
🔗 直达
BM74
复原 IP 地址
三重循环枚举三段分割
O(1)
O(1)
剪枝提前结束
🔗 直达
BM75
编辑距离(一)
二维 DP 经典 Levenshtein
O(n·m)
O(n·m)
可滚动数组优化
🔗 直达
BM76
正则表达式匹配
二维 DP:处理 *
和 .
O(n·m)
O(n·m)
状态转移分三种情况
🔗 直达
BM77
最长括号子串
栈 / 线性 DP
O(n)
O(n) / O(1)
栈存索引或 DP 分段累加
🔗 直达
BM78
打家劫舍(一)
线性 DP:不相邻取数
O(n)
O(1)
dp[i]=max(dp[i-1],dp[i-2]+nums[i-1])
🔗 直达
BM79
打家劫舍(二)
环形 DP:拆成两段线性 DP
O(n)
O(1)
两次 DP 取 max
🔗 直达
BM80
买卖股票(一)
一次交易 DP / 贪心
O(n)
O(1)
minPrice 贪心写法更简洁
🔗 直达
BM81
买卖股票(二)
无限交易贪心 / DP
O(n)
O(1)
贪心:累加所有上升段
🔗 直达
BM82
买卖股票(三)
最多两次交易状态机 DP
O(n)
O(1)
5 个状态滚动更新
🔗 直达
✅ 复习顺序建议(由易到难) BM62 → BM63 → BM64 → BM69 → BM67 → BM68 → BM70 → BM71 → BM72 → BM77 → BM78 → BM79 → BM80 → BM81 → BM82 → BM65 → BM66 → BM75 → BM76
BM62 斐波那契数列
斐波那契数列_牛客题霸_牛客网https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int Fibonacci (int n) { List<Integer> fib = new ArrayList <Integer>(); fib.add(0 ); fib.add(1 ); for (int i = 2 ; i <= n; i++) { fib.add(fib.get(i - 1 ) + fib.get(i - 2 )); } return fib.get(n); } }
空间优化 动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int Fibonacci (int n) { if (n <= 1 ) return n; int a = 0 , b = 1 , c = 0 ; for (int i = 2 ; i <= n; i++) { c = a + b; a = b; b = c; } return c; } }
递归
1 2 3 4 5 6 7 8 9 10 11 public class Solution { public int Fibonacci (int n) { if (n <= 1 ) return n; else { return Fibonacci(n - 1 ) + Fibonacci(n - 2 ); } } }
BM63 跳台阶
跳台阶_牛客题霸_牛客网https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int jumpFloor (int number) { List<Integer> dp = new ArrayList <>(); dp.add(1 ); dp.add(1 ); for (int i = 2 ; i <= 40 ; i++) { dp.add(dp.get(i - 1 ) + dp.get(i - 2 )); } return dp.get(number); } }
BM64 最小花费爬楼梯
最小花费爬楼梯_牛客题霸_牛客网https://www.nowcoder.com/practice/6fe0302a058a4e4a834ee44af88435c7?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj 2025年8月23日20:51:18 2025年8月23日20:57:18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.*;public class Solution { public int minCostClimbingStairs (int [] cost) { int n = cost.length; int [] dp = new int [n + 1 ]; dp[0 ] = 0 ; dp[1 ] = 0 ; for (int i = 2 ; i <= n; i++) { dp[i] = Math.min(dp[i - 1 ] + cost[i - 1 ], dp[i - 2 ] + cost[i - 2 ]); } return dp[n]; } }
BM65 最长公共子序列(二)
最长公共子序列(二)_牛客题霸_牛客网https://www.nowcoder.com/practice/6d29638c85bb4ffd80c020fe244baf11?tpId=295&tqId=991075&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import java.util.*;public class Solution { String x = "" ; String y = "" ; String ans (int l1, int l2, int [][] b) { String res = "" ; if (l1 == 0 || l2 == 0 ) { return res; } if (b[l1][l2] == 1 ) { res += ans(l1 - 1 , l2 - 1 , b); res += x.charAt(l1 - 1 ); } else if (b[l1][l2] == 2 ) { res += ans(l1 - 1 , l2, b); } else { res += ans(l1, l2 - 1 , b); } return res; } public String LCS (String s1, String s2) { int l1 = s1.length(); int l2 = s2.length(); if (l1 == 0 || l2 == 0 ) { return "-1" ; } x = s1; y = s2; int [][] dp = new int [l1 + 1 ][l2 + 1 ]; int [][] b = new int [l1 + 1 ][l2 + 1 ]; for (int i = 1 ; i <= l1; i++) { for (int j = 1 ; j <= l2; j++) { if (s1.charAt(i - 1 ) == s2.charAt(j - 1 )) { dp[i][j] = dp[i - 1 ][j - 1 ] + 1 ; b[i][j] = 1 ; } else { if (dp[i - 1 ][j] > dp[i][j - 1 ]) { dp[i][j] = dp[i - 1 ][j]; b[i][j] = 2 ; } else { dp[i][j] = dp[i][j - 1 ]; b[i][j] = 3 ; } } } } String res = ans(l1, l2, b); if (res.isEmpty()) { return "-1" ; } return res; } }
BM66 最长公共子串
最长公共子串_牛客题霸_牛客网https://www.nowcoder.com/practice/f33f5adc55f444baa0e0ca87ad8a6aac?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.*;public class Solution { public String LCS (String str1, String str2) { int [][] dp = new int [str1.length() + 1 ][str2.length() + 1 ]; int max = 0 ; int pos = 0 ; for (int i = 1 ; i <= str1.length(); i++) { for (int j = 1 ; j <= str2.length(); j++) { if (str1.charAt(i - 1 ) == str2.charAt(j - 1 )) { dp[i][j] = dp[i - 1 ][j - 1 ] + 1 ; if (dp[i][j] > max) { max = dp[i][j]; pos = i - 1 ; } } else { dp[i][j] = 0 ; } } } return str1.substring(pos - max + 1 , pos + 1 ); } }
BM67 不同路径的数目(一)
不同路径的数目(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/166eaff8439d4cd898e3ba933fbc6358?tpId=295&tqId=685&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.*;public class Solution { public int uniquePaths (int m, int n) { int [][] dp = new int [m + 1 ][n + 1 ]; dp[0 ][0 ] = 1 ; for (int i = 1 ; i < m; i++) { dp[i][0 ] = 1 ; } for (int i = 1 ; i < n; i++) { dp[0 ][i] = 1 ; } for (int i = 1 ; i < m; i++) { for (int j = 1 ; j < n; j++) { dp[i][j] = dp[i - 1 ][j] + dp[i][j - 1 ]; } } return dp[m - 1 ][n - 1 ]; } }
组合数学
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public int uniquePaths (int m, int n) { long res = 1 ; int x = n, y = 1 ; while (y < m) { res = res * x / y; x++; y++; } return (int ) res; } }
BM68 矩阵的最小路径和
矩阵的最小路径和_牛客题霸_牛客网https://www.nowcoder.com/practice/7d21b6be4c6b429bb92d219341c4f8bb?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.*;public class Solution { public int minPathSum (int [][] matrix) { int m = matrix.length; int n = matrix[0 ].length; 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[0 ][0 ] = matrix[0 ][0 ]; } else if (i == 0 ) { dp[i][j] = matrix[i][j] + dp[i][j - 1 ]; } else if (j == 0 ) { dp[i][j] = matrix[i][j] + dp[i - 1 ][j]; } else { dp[i][j] = Math.min(dp[i][j - 1 ], dp[i - 1 ][j]) + matrix[i][j]; } } } return dp[m - 1 ][n - 1 ]; } }
直接在原数组上修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public int minPathSum (int [][] matrix) { int m = matrix.length; int n = matrix[0 ].length; for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (i == 0 && j == 0 ) { continue ; } else if (i == 0 ) { matrix[i][j] += matrix[i][j - 1 ]; } else if (j == 0 ) { matrix[i][j] += matrix[i - 1 ][j]; } else { matrix[i][j] += Math.min(matrix[i][j - 1 ], matrix[i - 1 ][j]); } } } return matrix[m - 1 ][n - 1 ]; } }
BM69 把数字翻译成字符串
把数字翻译成字符串_牛客题霸_牛客网https://www.nowcoder.com/practice/046a55e6cd274cffb88fc32dba695668?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public int solve (String nums) { int n = nums.length(); if (nums.charAt(0 ) == '0' || n == 0 ) return 0 ; int [] dp = new int [n + 1 ]; dp[0 ] = 1 ; for (int i = 1 ; i < n; i++) { if (nums.charAt(i) != '0' ) dp[i] = dp[i - 1 ]; int t = (nums.charAt(i - 1 ) - '0' ) * 10 + (nums.charAt(i) - '0' ); if (t >= 10 && t <= 26 ) { if (i == 1 ) { dp[i] += 1 ; } else { dp[i] += dp[i - 2 ]; } } } return dp[n - 1 ]; } }
BM70 兑换零钱(一)
兑换零钱(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/3911a20b3f8743058214ceaa099eeb45?tpId=295&tqId=988994&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.*;public class Solution { public int minMoney (int [] arr, int aim) { if (aim < 1 ) return 0 ; int [] dp = new int [aim + 1 ]; Arrays.fill(dp, 0x3f3f3f ); dp[0 ] = 0 ; for (int i = 1 ; i <= aim; i++) { for (int j = 0 ; j < arr.length; j++) { if (i - arr[j] >= 0 ) dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1 ); } } return dp[aim] == 0x3f3f3f ? -1 : dp[aim]; } }
BM71 最长上升子序列(一)
最长上升子序列(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/5164f38b67f846fb8699e9352695cd2f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public int LIS (int [] arr) { int n = arr.length; if (n == 0 ) return 0 ; int [] dp = new int [n]; Arrays.fill(dp, 1 ); int maxl = 1 ; for (int i = 1 ; i < n; i++) { for (int j = 0 ; j < i; j++) { if (arr[i] > arr[j] && dp[i] < dp[j] + 1 ) { dp[i] = dp[j] + 1 ; maxl = Math.max(maxl, dp[i]); } } } return maxl; } }
BM72 连续子数组的最大和
连续子数组的最大和_牛客题霸_牛客网https://www.nowcoder.com/practice/459bd355da1549fa8a49e350bf3df484?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public int FindGreatestSumOfSubArray (int [] array) { int n = array.length; int [] dp = new int [n]; dp[0 ] = array[0 ]; int maxsum = array[0 ]; for (int i = 1 ; i < n; i++) { dp[i] = Math.max(dp[i - 1 ] + array[i], array[i]); maxsum = Math.max(maxsum, dp[i]); } return maxsum; } }
优化空间动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int FindGreatestSumOfSubArray (int [] array) { int n = array.length; int sum = 0 ; int maxsum = array[0 ]; for (int i = 0 ; i < n; i++) { sum = Math.max(sum, 0 ) + array[i]; maxsum = Math.max(maxsum, sum); } return maxsum; } }
BM73 最长回文子串
最长回文子串_牛客题霸_牛客网https://www.nowcoder.com/practice/b4525d1d84934cf280439aeecc36f4af?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
中心拓展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public int fun (String s, int b, int e) { while (b >= 0 && e < s.length() && s.charAt(b) == s.charAt(e)) { b--; e++; } return e - b - 1 ; } public int getLongestPalindrome (String A) { int maxl = 1 ; for (int i = 0 ; i < A.length() - 1 ; i++) { maxl = Math.max(maxl, Math.max(fun(A, i, i), fun(A, i, i + 1 ))); } return maxl; } }
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public int getLongestPalindrome (String a) { int n = a.length(); boolean [][] f = new boolean [n][n]; int max = 0 ; for (int c = 0 ; c < n; c++) { for (int i = 0 ; i < n - c; i++) { int j = c + i; if (a.charAt(i) == a.charAt(j)) { if (c <= 1 ) f[i][j] = true ; else f[i][j] = f[i + 1 ][j - 1 ]; if (f[i][j]) max = c + 1 ; } } } return max; } }
马拉车
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 import java.util.*;public class Solution { public int getLongestPalindrome (String s) { int n = s.length(); char [] t = new char [n * 2 + 3 ]; Arrays.fill(t, '#' ); t[0 ] = '^' ; for (int i = 0 ; i < n; i++) { t[i * 2 + 2 ] = s.charAt(i); } t[n * 2 + 2 ] = '$' ; int [] hl = new int [t.length - 2 ]; hl[1 ] = 1 ; int maxi = 0 ; int boxm = 0 ; int boxr = 0 ; for (int i = 2 ; i < hl.length; i++) { int tmpl = 1 ; if (i < boxr) { tmpl = Math.min(hl[boxm * 2 - i], boxr - i); } while (t[i - tmpl] == t[i + tmpl]) { tmpl++; boxm = i; boxr = i + tmpl; } hl[i] = tmpl; if (tmpl > hl[maxi]) { maxi = i; } } int ansl = hl[maxi]; return (maxi + ansl) / 2 - 1 - (maxi - ansl) / 2 ; } }
BM74 数字字符串转化成IP地址
数字字符串转化成IP地址_牛客题霸_牛客网https://www.nowcoder.com/practice/ce73540d47374dbe85b3125f57727e1e?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import java.util.*;public class Solution { boolean chk (String s) { return Integer.parseInt(s) > 255 ; } boolean chk2 (String s) { return s.length() != 1 && s.charAt(0 ) == '0' ; } public ArrayList<String> restoreIpAddresses (String s) { LinkedList<String> res = new LinkedList <String>(); int n = s.length(); for (int i = 1 ; i < 4 && i < n - 2 ; i++) { for (int j = i + 1 ; j < i + 4 && j < n - 1 ; j++) { for (int k = j + 1 ; k < j + 4 && k < n; k++) { if (n - k >= 4 ) continue ; String a = s.substring(0 , i); String b = s.substring(i, j); String c = s.substring(j, k); String d = s.substring(k); if (chk(a) || chk(b) || chk(c) || chk(d)) continue ; if (chk2(a) || chk2(b) || chk2(c) || chk2(d)) continue ; String cur = a + '.' + b + '.' + c + '.' + d; res.addLast(cur); } } } return new ArrayList <>(res); } }
BM75 编辑距离(一)
编辑距离(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/6a1483b5be1547b1acd7940f867be0da?tpId=295&tqId=2294660&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import java.util.*;public class Solution { public int editDistance (String str1, String str2) { int n1 = str1.length(); int n2 = str2.length(); int [][] d = new int [n1 + 1 ][n2 + 1 ]; d[0 ][0 ] = 0 ; for (int i = 1 ; i <= n1; i++) { d[i][0 ] = d[i - 1 ][0 ] + 1 ; } for (int i = 1 ; i <= n2; i++) { d[0 ][i] = d[0 ][i - 1 ] + 1 ; } for (int i = 1 ; i <= n1; i++) { for (int j = 1 ; j <= n2; j++) { if (str1.charAt(i - 1 ) == str2.charAt(j - 1 )) { d[i][j] = d[i - 1 ][j - 1 ]; } else { d[i][j] = Math.min(d[i - 1 ][j], Math.min(d[i][j - 1 ], d[i - 1 ][j - 1 ])) + 1 ; } } } return d[n1][n2]; } }
压缩空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java.util.*;public class Solution { public int editDistance (String str1, String str2) { int n1 = str1.length(); int n2 = str2.length(); int [][] f = new int [2 ][n2 + 1 ]; for (int i = 1 ; i <= n2; i++) { f[0 ][i] = i; } for (int i = 1 ; i <= n1; i++) { for (int j = 1 ; j <= n2; j++) { if (str1.charAt(i - 1 ) == str2.charAt(j - 1 )) { if (j - 1 == 0 ) f[i % 2 ][j] = i - 1 ; else f[i % 2 ][j] = f[(i + 1 ) % 2 ][j - 1 ]; } else { if (j - 1 == 0 ) f[i % 2 ][j] = Math.min(f[(i + 1 ) % 2 ][j] + 1 , i); else f[i % 2 ][j] = Math.min(f[(i + 1 ) % 2 ][j], Math.min(f[(i + 1 ) % 2 ][j - 1 ], f[i % 2 ][j - 1 ])) + 1 ; } } } return f[n1 % 2 ][n2]; } }
BM76 正则表达式匹配
正则表达式匹配_牛客题霸_牛客网https://www.nowcoder.com/practice/28970c15befb4ff3a264189087b99ad4?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.*;public class Solution { public boolean match (String str, String pattern) { int n1 = str.length(); int n2 = pattern.length(); str = " " + str; pattern = " " + pattern; char [] s = str.toCharArray(); char [] p = pattern.toCharArray(); boolean [][] f = new boolean [n1 + 1 ][n2 + 1 ]; f[0 ][0 ] = true ; for (int i = 0 ; i <= n1; i++) { for (int j = 1 ; j <= n2; j++) { if (j + 1 <= n2 && p[j + 1 ] == '*' ) continue ; if (i - 1 >= 0 && p[j] != '*' ) { f[i][j] = f[i - 1 ][j - 1 ] && (s[i] == p[j] || p[j] == '.' ); } else if (p[j] == '*' ) { f[i][j] = (j - 2 >= 0 && f[i][j - 2 ]) || (i - 1 >= 0 && f[i - 1 ][j] && (s[i] == p[j - 1 ] || p[j - 1 ] == '.' )); } } } return f[n1][n2]; } }
BM77 最长的括号子串
最长的括号子串_牛客题霸_牛客网https://www.nowcoder.com/practice/45fd68024a4c4e97a8d6c45fc61dc6ad?tpId=295&tqId=715&sourceUrl=%2Fexam%2Foj
栈匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public int longestValidParentheses (String s) { int res = 0 ; int st = -1 ; Stack<Integer> stk = new Stack <Integer>(); for (int i = 0 ; i < s.length(); i++) { if (s.charAt(i) == '(' ) stk.push(i); else { if (stk.isEmpty()) st = i; else { stk.pop(); if (!stk.isEmpty()) { res = Math.max(res, i - stk.peek()); } else res = Math.max(res, i - st); } } } return res; } }
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public int longestValidParentheses (String s) { int ans = 0 ; int n = s.length(); if (n == 0 || s == null ) return ans; int [] f = new int [n + 1 ]; for (int i = 1 ; i < n; i++) { if (s.charAt(i) == ')' ) { if (s.charAt(i - 1 ) == '(' ) { f[i] = (i >= 2 ? f[i - 2 ] : 0 ) + 2 ; } else if (i - f[i - 1 ] > 0 && s.charAt(i - f[i - 1 ] - 1 ) == '(' ) { f[i] = (i - f[i - 1 ] > 1 ? f[i - f[i - 1 ] - 2 ] : 0 ) + f[i - 1 ] + 2 ; } } ans = Math.max(ans, f[i]); } return ans; } }
BM78 打家劫舍(一)
打家劫舍(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/c5fbf7325fbd4c0ea3d0c3ea6bc6cc79?tpId=295&tqId=2285793&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public int rob (int [] nums) { int n = nums.length; if (n == 0 ) return 0 ; if (n == 1 ) return nums[0 ]; int [] f = new int [n + 1 ]; f[1 ] = nums[0 ]; for (int i = 2 ; i <= n; i++) { f[i] = Math.max(f[i - 2 ] + nums[i - 1 ], f[i - 1 ]); } return f[n]; } }
BM79 打家劫舍(二)
https://www.nowcoder.com/practice/a5c127769dd74a63ada7bff37d9c5815?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public int rob (int [] nums) { if (nums.length == 0 ) return 0 ; if (nums.length == 1 ) return nums[0 ]; int [] f = new int [nums.length + 1 ]; f[1 ] = nums[0 ]; for (int i = 2 ; i < nums.length; i++) { f[i] = Math.max(f[i - 1 ], nums[i - 1 ] + f[i - 2 ]); } int res = f[nums.length - 1 ]; Arrays.fill(f, 0 ); f[1 ] = 0 ; for (int i = 2 ; i <= nums.length; i++) { f[i] = Math.max(f[i - 1 ], nums[i - 1 ] + f[i - 2 ]); } return Math.max(res, f[nums.length]); } }
BM80 买卖股票的最好时机(一)
买卖股票的最好时机(一)_牛客题霸_牛客网https://www.nowcoder.com/practice/64b4262d4e6d4f6181cd45446a5821ec?tpId=295&tqId=625&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public int maxProfit (int [] prices) { int n = prices.length; if (n == 0 ) return 0 ; int [][] dp = new int [n][2 ]; dp[0 ][0 ] = 0 ; dp[0 ][1 ] = -prices[0 ]; for (int i = 1 ; i < n; i++) { dp[i][0 ] = Math.max(dp[i - 1 ][0 ], dp[i - 1 ][1 ] + prices[i]); dp[i][1 ] = Math.max(dp[i - 1 ][1 ], -prices[i]); } return dp[n - 1 ][0 ]; } }
贪心 + 找当前最小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int maxProfit (int [] prices) { int minp = Integer.MAX_VALUE; int ans = 0 ; for (int p : prices) { ans = Math.max(ans, p - minp); minp = Math.min(minp, p); } return ans; } }
BM81 买卖股票的最好时机(二)
买卖股票的最好时机(二)_牛客题霸_牛客网https://www.nowcoder.com/practice/9e5e3c2603064829b0a0bbfca10594e9?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
动态规划
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public int maxProfit (int [] prices) { int n = prices.length; if (n == 0 ) return 0 ; int [][] f = new int [n][2 ]; f[0 ][0 ] = 0 ; f[0 ][1 ] = -prices[0 ]; for (int i = 1 ; i < n; i++) { f[i][0 ] = Math.max(f[i - 1 ][0 ], f[i - 1 ][1 ] + prices[i]); f[i][1 ] = Math.max(f[i - 1 ][1 ], f[i - 1 ][0 ] - prices[i]); } return f[n - 1 ][0 ]; } }
贪心 + 只要是单增 就是赚的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.util.*;public class Solution { public int maxProfit (int [] prices) { int ans = 0 ; for (int i = 1 ; i < prices.length; i++) { if (prices[i] > prices[i - 1 ]) { ans += prices[i] - prices[i - 1 ]; } } return ans; } }
BM82 买卖股票的最好时机(三)
买卖股票的最好时机(三)_牛客题霸_牛客网https://www.nowcoder.com/practice/4892d3ff304a4880b7a89ba01f48daf9?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;public class Solution { public int maxProfit (int [] prices) { int n = prices.length; if (n == 0 ) return 0 ; int [][] f = new int [n][5 ]; Arrays.fill(f[0 ], -200000 * 100 ); f[0 ][0 ] = 0 ; f[0 ][1 ] = -prices[0 ]; for (int i = 1 ; i < n; i++) { f[i][0 ] = f[i - 1 ][0 ]; f[i][1 ] = Math.max(f[i - 1 ][1 ], f[i - 1 ][0 ] - prices[i]); f[i][2 ] = Math.max(f[i - 1 ][2 ], f[i - 1 ][1 ] + prices[i]); f[i][3 ] = Math.max(f[i - 1 ][3 ], f[i - 1 ][2 ] - prices[i]); f[i][4 ] = Math.max(f[i - 1 ][4 ], f[i - 1 ][3 ] + prices[i]); } return Math.max(0 , Math.max(f[n - 1 ][4 ], f[n - 1 ][2 ])); } }
字符串
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM83
字符串变形
两次反转:先整体反转,再按空格反转单词
O(n)
O(n)
使用 StringBuffer 便于反转和替换;先整体后局部反转思路清晰
🔗 直达
BM84
最长公共前缀
1. 纵向扫描(逐位比较) 2. 二分优化(前缀长度二分)
O(S) / O(S·log L)
O(1) / O(1)
纵向扫描思路直观;二分优化适合前缀较短场景;空间均为 O(1)
🔗 直达
BM85
验证IP地址
1. 条件枚举逐段检查 2. 正则表达式一次性匹配
O(1)
O(1)
枚举法逻辑清晰易调试;正则法代码简洁但可读性稍差
🔗 直达
BM86
大数加法
1. 两次翻转+进位 2. 倒序遍历+进位 3. 栈+进位
O(max(len1,len2))
O(max(len1,len2))
倒序遍历无需显式翻转字符串;栈写法天然逆序处理;均支持超大整数
🔗 直达
✅ 复习顺序建议(由易到难) BM84 → BM85 → BM86 → BM83
BM83 字符串变形
字符串变形_牛客题霸_牛客网https://www.nowcoder.com/practice/c3120c1c1bc44ad986259c0cf0f0b80e?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.*;public class Solution { public String trans (String s, int n) { if (n == 0 ) return s; StringBuffer sb = new StringBuffer (); for (int i = 0 ; i < n; i++) { if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z' ) sb.append((char ) (s.charAt(i) - 'a' + 'A' )); else if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z' ) sb.append((char ) (s.charAt(i) - 'A' + 'a' )); else sb.append(s.charAt(i)); } sb = sb.reverse(); for (int i = 0 ; i < n; i++) { int j = i; while (j < n && sb.charAt(j) != ' ' ) j++; String tmp = sb.substring(i, j); StringBuffer stringBuffer = new StringBuffer (tmp); tmp = stringBuffer.reverse().toString(); sb.replace(i, j, tmp); i = j; } return sb.toString(); } }
BM84 最长公共前缀
最长公共前缀_牛客题霸_牛客网https://www.nowcoder.com/practice/28eb3175488f4434a4a6207f6f484f47?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.*;public class Solution { public String longestCommonPrefix (String[] strs) { int n = strs.length; if (n == 0 ) return "" ; for (int i = 0 ; i < strs[0 ].length(); i++) { char tmp = strs[0 ].charAt(i); for (int j = 1 ; j < n; j++) { if (i == strs[j].length() || strs[j].charAt(i) != tmp) { return strs[0 ].substring(0 , i); } } } return strs[0 ]; } }
二分优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { boolean isPre (String[] s, int len) { String s0 = s[0 ].substring(0 , len); int cnt = s.length; for (int i = 1 ; i < cnt; i++) { String str = s[i]; for (int j = 0 ; j < len; j++) { if (s0.charAt(j) != str.charAt(j)) { return false ; } } } return true ; } public String longestCommonPrefix (String[] strs) { if (strs == null || strs.length == 0 ) return "" ; int minlen = Integer.MAX_VALUE; for (String s : strs) minlen = Math.min(minlen, s.length()); int l = 0 , r = minlen; while (l < r) { int mid = (r - l + 1 ) / 2 + l; if (isPre(strs, mid)) { l = mid; } else { r = mid - 1 ; } } return strs[0 ].substring(0 , l); } }
BM85 验证IP地址
验证IP地址_牛客题霸_牛客网https://www.nowcoder.com/practice/55fb3c68d08d46119f76ae2df7566880?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
按照条件枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import java.util.*;public class Solution { public String solve (String IP) { boolean mayIPv4 = false ; boolean mayIPv6 = false ; if (IP.contains("." )) mayIPv4 = true ; if (IP.contains(":" )) mayIPv6 = true ; if (mayIPv4) { String[] a = IP.split("\\." ); if (IP.charAt(0 ) == '.' || IP.charAt(IP.length() - 1 ) == '.' ) return "Neither" ; if (a.length != 4 ) return "Neither" ; for (int i = 0 ; i < 4 ; i++) { if (a[i].charAt(0 ) == '0' && a[i].length() > 1 ) return "Neither" ; int sum = 0 ; for (int j = 0 ; j < a[i].length(); j++) { sum = sum * 10 + (a[i].charAt(j) - '0' ); } if (sum > 255 ) { return "Neither" ; } } return "IPv4" ; } if (mayIPv6) { String[] b = IP.split(":" ); if (IP.charAt(0 ) == ':' || IP.charAt(IP.length() - 1 ) == ':' ) return "Neither" ; if (b.length != 8 ) return "Neither" ; for (int i = 0 ; i < 8 ; i++) { if (b[i].length() == 0 || b[i].length() > 4 ) return "Neither" ; for (int j = 0 ; j < b[i].length(); j++) { if (!((b[i].charAt(j) >= '0' && b[i].charAt(j) <= '9' ) || (b[i].charAt(j) >= 'A' && b[i].charAt(j) <= 'F' ) || (b[i].charAt(j) >= 'a' && b[i].charAt(j) <= 'f' ))) { return "Neither" ; } } } return "IPv6" ; } return "Neither" ; } }
正则表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.*;import java.util.regex.*;public class Solution { public String solve (String IP) { String ipv4 = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" ; Pattern ipv4p = Pattern.compile(ipv4); String ipv6 = "([0-9a-fA-F]{1,4}\\:){7}([0-9a-fA-F]{1,4})" ; Pattern ipv6p = Pattern.compile(ipv6); if (ipv4p.matcher(IP).matches()) { return "IPv4" ; } else if (ipv6p.matcher(IP).matches()) { return "IPv6" ; } return "Neither" ; } }
BM86 大数加法
大数加法_牛客题霸_牛客网https://www.nowcoder.com/practice/11ae12e8c6fe48f883cad618c2e81475?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
两次翻转 + 枚举 + 进位标记
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { String rev (String s) { StringBuffer sb = new StringBuffer (); for (int i = s.length() - 1 ; i >= 0 ; i--) { sb.append(s.charAt(i)); } return sb.toString(); } public String solve (String s, String t) { int l1 = s.length(); int l2 = t.length(); if (l1 == 0 ) return t; if (l2 == 0 ) return s; s = rev(s); t = rev(t); StringBuffer sb = new StringBuffer (); int curry = 0 ; for (int i = 0 ; i < Math.max(l1, l2); i++) { int s1 = (i < l1) ? s.charAt(i) - '0' : 0 ; int s2 = (i < l2) ? t.charAt(i) - '0' : 0 ; int sum = s1 + s2 + curry; curry = 0 ; sb.append(sum % 10 ); if (sum >= 10 ) curry = 1 ; } if (curry == 1 ) sb.append(curry); String res = sb.toString(); return rev(res); } }
倒序遍历 + 进位标记 + 翻转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public String solve (String s, String t) { int l1 = s.length(); int l2 = t.length(); if (l1 == 0 ) return t; if (l2 == 0 ) return s; StringBuffer sb = new StringBuffer (); int curry = 0 ; for (int i = 0 ; i < Math.max(l1, l2); i++) { int s1 = (i < l1) ? s.charAt(l1 - 1 - i) - '0' : 0 ; int s2 = (i < l2) ? t.charAt(l2 - 1 - i) - '0' : 0 ; int sum = s1 + s2 + curry; sb.append(sum % 10 ); curry = (sum >= 10 ) ? 1 : 0 ; } if (curry == 1 ) sb.append(curry); String res = sb.reverse().toString(); return res; } }
栈 + 进位标记 + 倒序遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.*;public class Solution { public String solve (String s, String t) { int l1 = s.length(); int l2 = t.length(); Stack<Integer> st = new Stack <>(); StringBuffer sb = new StringBuffer (); int curry = 0 ; for (int i = 0 ; i < Math.max(l1,l2) ; i ++){ int s1 = (i < l1) ? s.charAt(l1 - 1 - i) - '0' : 0 ; int s2 = (i < l2) ? t.charAt(l2 - 1 - i) - '0' : 0 ; int sum = s1 + s2 + curry ; st.add(sum % 10 ); curry = (sum >= 10 ) ? 1 :0 ; } if (curry == 1 )st.add(curry); while (!st.isEmpty()) sb.append(st.pop()); return sb.toString(); } }
双指针
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM87
合并两个有序的数组
逆向双指针,原地归并
O(m+n)
O(1)
从尾部填充,避免覆盖未处理元素
🔗 直达
BM88
判断是否为回文字符串
左右双指针相向扫描
O(n)
O(1)
字符数组随机访问,发现不匹配立即返回
🔗 直达
BM89
合并区间
排序 + 贪心扫描
O(n log n)
O(n)
按 start 升序排序,重叠即合并,一次遍历完成
🔗 直达
BM90
最小覆盖子串
滑动窗口 + 哈希/数组计数
O(
S
+
T
BM91
反转字符串
双指针交换 / StringBuffer.reverse
O(n)
O(1) / O(n)
原地交换无需额外空间;StringBuffer 一行代码版
🔗 直达
BM92
最长无重复子数组
滑动窗口 + HashMap 计数
O(n)
O(n)
右指针扩展,出现重复时左指针收缩,一次遍历求最大长度
🔗 直达
BM93
盛水最多的容器
双指针夹逼法
O(n)
O(1)
短板向内移动才可能得到更大面积,数学证明保证最优
🔗 直达
BM94
接雨水问题
双指针 + 左右最大高度
O(n)
O(1)
维护左右最大值,低侧先结算,避免使用栈或额外数组
🔗 直达
✅ 复习顺序建议(由易到难) BM91 → BM88 → BM87 → BM92 → BM93 → BM94 → BM89 → BM90
BM87 合并两个有序的数组
合并两个有序的数组_牛客题霸_牛客网https://www.nowcoder.com/practice/89865d4375634fc484f3a24b7fe65665?tpId=295&tqId=658&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.*;public class Solution { public void merge (int A[], int m, int B[], int n) { int a = m - 1 ; int b = n - 1 ; for (int i = m + n - 1 ; i >= 0 ; i--) { if (b < 0 || (a >= 0 && A[a] >= B[b])) { A[i] = A[a]; a--; } else { A[i] = B[b]; b--; } } } }
BM88 判断是否为回文字符串 判断是否为回文字符串_牛客题霸_牛客网https://www.nowcoder.com/practice/e297fdd8e9f543059b0b5f05f3a7f3b2?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public boolean judge (String str) { int l = 0 ; int r = str.length() - 1 ; char [] a = str.toCharArray(); while (l <= r) { if (a[l] != a[r]) return false ; l++; r--; } return true ; } }
BM89 合并区间
合并区间_牛客题霸_牛客网https://www.nowcoder.com/practice/69f4e5b7ad284a478777cb2a17fb5e6a?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
排序 + 贪心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import java.util.*;public class Solution { public ArrayList<Interval> merge (ArrayList<Interval> is) { ArrayList<Interval> ans = new ArrayList <>(); if (is.size() == 0 ) return ans; Collections.sort(is, new Comparator <Interval>() { public int compare (Interval o1, Interval o2) { if (o1.start != o2.start) return o1.start - o2.start; return o1.end - o2.end; } }); ans.add(is.get(0 )); int cnt = 0 ; for (int i = 1 ; i < is.size(); i++) { Interval curr = is.get(i); Interval last = ans.get(cnt); if (curr.start > last.end) { ans.add(curr); cnt++; } else { int newStart = last.start; int newEnd = Math.max(curr.end, last.end); ans.remove(cnt); ans.add(new Interval (newStart, newEnd)); } } return ans; } }
BM90 最小覆盖子串
最小覆盖子串_牛客题霸_牛客网https://www.nowcoder.com/practice/c466d480d20c4c7c9d322d12ca7955ac?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
哈希表记录 + 双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import java.util.*;public class Solution { boolean chk (Map<Character, Integer> map) { for (Map.Entry<Character, Integer> e : map.entrySet()) { if (e.getValue() < 0 ) return false ; } return true ; } public String minWindow (String S, String T) { Map<Character, Integer> map = new HashMap <>(); int n1 = T.length(); int n2 = S.length(); for (int i = 0 ; i < n1; i++) { map.merge(T.charAt(i), -1 , Integer::sum); } int i = 0 ; int l = -1 , r = -1 ; int cnt = 0x3f3f3f ; for (int j = 0 ; j < n2; j++) { map.merge(S.charAt(j), 1 , Integer::sum); while (chk(map)) { if (cnt > j - i + 1 ) { cnt = j - i + 1 ; l = i; r = j; } map.merge(S.charAt(i), -1 , Integer::sum); i++; } } return (l == -1 ) ? "" : S.substring(l, r + 1 ); } }
数组记录 + 双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import java.util.*;public class Solution { static int [] cnt = new int [128 ]; boolean chk () { for (int i = 0 ; i < 128 ; i++) if (cnt[i] < 0 ) return false ; return true ; } public String minWindow (String S, String T) { Arrays.fill(cnt, 0 ); for (int i = 0 ; i < T.length(); i++) cnt[T.charAt(i)]--; int s = 0 , f = 0 ; int l = -1 , r = -1 ; int count = 0x3f3f3f ; while (f < S.length()) { cnt[S.charAt(f)]++; while (chk()) { if (count > f + 1 - s) { count = f + 1 - s; l = s; r = f; } cnt[S.charAt(s)]--; s++; } f++; } if (l == -1 ) return "" ; return S.substring(l, r + 1 ); } }
BM91 反转字符串
反转字符串_牛客题霸_牛客网https://www.nowcoder.com/practice/c3a6afee325e472386a1c4eb1ef987f3?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
双指针翻转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.*;public class Solution { public String solve (String str) { char [] ans = str.toCharArray(); int l = 0 , r = ans.length - 1 ; while (l < r) { char tmp = ans[l]; ans[l] = ans[r]; ans[r] = tmp; l++; r--; } return new String (ans); } }``` 2. StringBuffer 翻转```java import java.util.*;public class Solution { public String solve (String str) { StringBuffer sb = new StringBuffer (); for (char ch : str.toCharArray()) sb.append(ch); return sb.reverse().toString(); } }
BM92 最长无重复子数组
最长无重复子数组_牛客题霸_牛客网https://www.nowcoder.com/practice/b56799ebfd684fb394bd315e89324fb4?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public int maxLength (int [] arr) { Map<Integer,Integer> cnt = new HashMap <>(); int ans = 0 , l = 0 , r = 0 ; while (r < arr.length) { cnt.merge(arr[r], 1 , Integer::sum); while (cnt.get(arr[r]) > 1 ) cnt.merge(arr[l++], -1 , Integer::sum); ans = Math.max(ans, r - l + 1 ); r++; } return ans; } }
BM93 盛水最多的容器
盛水最多的容器_牛客题霸_牛客网https://www.nowcoder.com/practice/3d8d6a8e516e4633a2244d2934e5aa47?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.util.*;public class Solution { public int maxArea (int [] height) { if (height.length < 2 ) return 0 ; int l = 0 , r = height.length - 1 ; int ans = 0 ; while (l < r) { int lh = height[l], rh = height[r]; ans = Math.max(ans, Math.min(lh, rh) * (r - l)); if (lh < rh) l++; else r--; } return ans; } }
BM94 接雨水问题
接雨水问题_牛客题霸_牛客网https://www.nowcoder.com/practice/31c1aed01b394f0b8b7734de0324e00f?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.*;public class Solution { public long maxWater (int [] arr) { long ans = 0 ; int l = 0 , r = arr.length - 1 ; int lh = 0 , rh = 0 ; while (l < r) { lh = Math.max(lh, arr[l]); rh = Math.max(rh, arr[r]); if (lh < rh) { ans += lh - arr[l++]; } else { ans += rh - arr[r--]; } } return ans; } }
贪心算法
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM95
分糖果问题
两次贪心扫描:先左→右,再右→左
O(n)
O(n)
无需回溯,两次线性遍历即可满足相邻与高分的双重约束
🔗 直达
BM96
主持人调度(二)
贪心 + 双指针(或最小堆)
O(n log n)
O(n)
将起止时间拆开排序,扫描线思想;堆写法更直观
🔗 直达
✅ 复习顺序建议(由易到难) BM95 → BM96
BM95 分糖果问题
分糖果问题_牛客题霸_牛客网https://www.nowcoder.com/practice/76039109dd0b47e994c08d8319faa352?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public int candy (int [] arr) { int n = arr.length; if (n <= 1 ) return n; int [] ans = new int [n]; Arrays.fill(ans, 1 ); for (int i = 1 ; i < n; i++) { if (arr[i] > arr[i - 1 ]) ans[i] = ans[i - 1 ] + 1 ; } for (int i = n - 2 ; i >= 0 ; i--) { if (arr[i] > arr[i + 1 ] && ans[i] <= ans[i + 1 ]) ans[i] = ans[i + 1 ] + 1 ; } return Arrays.stream(ans).sum(); } }
BM96 主持人调度(二)
主持人调度(二)_牛客题霸_牛客网https://www.nowcoder.com/practice/4edf6e6d01554870a12f218c94e8a299?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
分开排序 + 计算区间的个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.*;public class Solution { public int minmumNumberOfHost (int n, int [][] startEnd) { int [] st = new int [n]; int [] ed = new int [n]; for (int i = 0 ; i < n; i++) { st[i] = startEnd[i][0 ]; ed[i] = startEnd[i][1 ]; } Arrays.sort(st); Arrays.sort(ed); int res = 0 ; int j = 0 ; for (int i = 0 ; i < n; i++) { if (st[i] >= ed[j]) { j++; } else { res++; } } return res; } }
重载排序+大顶堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util.*;public class Solution { public int minmumNumberOfHost (int n, int [][] startEnd) { Arrays.sort(startEnd, new Comparator <int []>() { public int compare (int [] o1, int [] o2) { return Integer.compare(o1[0 ], o2[0 ]); } }); PriorityQueue<Integer> pq = new PriorityQueue <>(); pq.offer(Integer.MIN_VALUE); for (int i = 0 ; i < n; i++) { if (pq.peek() <= startEnd[i][0 ]) { pq.poll(); } pq.offer(startEnd[i][1 ]); } return pq.size(); } }
模拟
题号
题目名称
核心思路
时间复杂度
空间复杂度
代码亮点
牛客原题链接
BM97
旋转数组
三次反转法
O(n)
O(1)
先整体反转,再局部反转两次,无需额外数组
🔗 直达
BM98
螺旋矩阵
模拟层遍历
O(n·m)
O(1)
用四个边界控制方向,注意单行/单列去重
🔗 直达
BM99
顺时针旋转矩阵
转置+水平翻转 或 直接映射
O(n²)
O(1) / O(n²)
两次翻转原地完成;一次映射写法更直观
🔗 直达
BM100
设计LRU缓存
哈希+双向链表
O(1)
O(capacity)
手写双向链表实现最近/最久节点移动;LinkedHashMap版简洁
🔗 直达
BM101
设计LFU缓存
哈希+频次双向链表+最小频次指针
O(1)
O(capacity)
维护freq→LinkedList映射,O(1)提频与淘汰
🔗 直达
✅ 复习顺序建议(由易到难) BM97 → BM98 → BM99 → BM100 → BM101
BM97 旋转数组
旋转数组_牛客题霸_牛客网https://www.nowcoder.com/practice/e19927a8fd5d477794dac67096862042?tpId=295&tqId=1024689&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.util.*;public class Solution { void rev (int [] a,int s,int e) { while (s < e){ int tmp = a[s]; a[s] = a[e]; a[e] = tmp; s ++;e--; } } public int [] solve (int n, int m, int [] a) { m %= n; rev(a,0 ,n - 1 ); rev(a,0 ,m - 1 ); rev(a,m ,n - 1 ); return a; } }
BM98 螺旋矩阵
螺旋矩阵_牛客题霸_牛客网https://www.nowcoder.com/practice/7edf70f2d29c4b599693dc3aaeea1d31?tpId=295&tqId=1024689&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.util.*;public class Solution { public ArrayList<Integer> spiralOrder (int [][] matrix) { ArrayList<Integer> ans = new ArrayList <Integer>(); if (matrix.length == 0 ) return ans; int m = matrix.length, n = matrix[0 ].length; int t = 0 , b = m - 1 , l = 0 , r = n - 1 ; while (t < (m + 1 ) / 2 && l < (n + 1 ) / 2 ) { for (int i = l; i <= r; i++) { ans.add(matrix[t][i]); } for (int i = t + 1 ; i <= b; i++) { ans.add(matrix[i][r]); } for (int i = r - 1 ; t != b && i >= l; i--) { ans.add(matrix[b][i]); } for (int i = b - 1 ; l != r && i >= t + 1 ; i--) { ans.add(matrix[i][l]); } t++; l++; b--; r--; } return ans; } }
BM99 顺时针旋转矩阵
顺时针旋转矩阵_牛客题霸_牛客网https://www.nowcoder.com/practice/2e95333fbdd4451395066957e24909cc?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
两次翻转 (主对角线 + 水平)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.*;public class Solution { public int [][] rotateMatrix (int [][] a, int n) { int l = a.length; for (int i = 0 ; i < l ; i ++){ for (int j = 0 ; j < i ; j ++){ int t = a[i][j]; a[i][j] = a[j][i]; a[j][i] = t; } } for (int i = 0 ; i < l; i ++){ for (int j = 0 ; j < l / 2 ; j ++){ int t = a[i][j]; a[i][j] = a[i][l - 1 - j]; a[i][l - 1 - j] = t; } } return a; } }
一次翻转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Solution { public int [][] rotateMatrix (int [][] a, int n) { int l = a.length; int [][] ans = new int [n][n]; for (int i = 0 ; i < l; i++) { for (int j = 0 ; j < l; j++) { ans[j][n - 1 - i] = a[i][j]; } } return ans; } }
BM100 设计LRU缓存结构
设计LRU缓存结构_牛客题霸_牛客网https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import java.util.*;public class Solution { int capacity = 0 ; Node head = null ; Node tail = null ; int used = 0 ; HashMap<Integer, Node> map = new HashMap <>(); class Node { int key; int val; Node pre; Node next; public Node (int k, int v) { key = k; val = v; pre = null ; next = null ; } } void update (int key) { Node t = map.get(key); if (t != head) { if (t == tail) { tail = tail.pre; tail.next = null ; } else { t.pre.next = t.next; t.next.pre = t.pre; } t.pre = null ; t.next = head; head.pre = t; head = t; } } void removelast () { map.remove(tail.key); tail = tail.pre; tail.next = null ; used--; } void insert (int key, int val) { if (head == null ) { head = new Node (key, val); tail = head; } else { Node t = new Node (key, val); t.pre = null ; t.next = head; head.pre = t; head = t; } } public Solution (int capacity) { this .capacity = capacity; this .map = new HashMap <>(); this .used = 0 ; } public int get (int key) { if (!map.containsKey(key)) { return -1 ; } update(key); return map.get(key).val; } public void set (int key, int val) { if (map.containsKey(key)) { map.get(key).val = val; update(key); return ; } if (used == capacity) { removelast(); } insert(key, val); map.put(key, head); used++; } }
内聚一个线程安全的 LRUCache 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import java.util.LinkedHashMap;import java.util.Map;public class Solution { private final LRUCache<Integer, Integer> cache; public Solution (int capacity) { this .cache = new LRUCache <>(capacity); } public int get (int key) { Integer val = cache.get(key); return val == null ? -1 : val; } public void set (int key, int value) { cache.put(key, value); } private static class LRUCache <K, V> extends LinkedHashMap <K, V> { private final int capacity; LRUCache(int capacity) { super (capacity, 0.75f , true ); this .capacity = capacity; } @Override protected boolean removeEldestEntry (Map.Entry<K, V> eldest) { return size() > capacity; } } }
BM101 设计LFU缓存结构
设计LFU缓存结构_牛客题霸_牛客网https://www.nowcoder.com/practice/93aacb4a887b46d897b00823f30bfea1?tpId=295&tags=&title=&difficulty=0&judgeStatus=0&rp=0&sourceUrl=%2Fexam%2Foj
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import java.util.*;public class Solution { static class N { int freq; int key; int val; public N (int f, int k, int v) { this .freq = f; this .key = k; this .val = v; } } Map<Integer, LinkedList<N>> freqmp = new HashMap <>(); Map<Integer, N> mp = new HashMap <>(); int size = 0 ; int minFreq = 0 ; void update (N n, int k, int v) { int freq = n.freq; freqmp.get(freq).remove(n); if (freqmp.get(freq).isEmpty()) { freqmp.remove(freq); if (minFreq == freq) minFreq++; } if (!freqmp.containsKey(freq + 1 )) freqmp.put(freq + 1 , new LinkedList <N>()); freqmp.get(freq + 1 ).addFirst(new N (freq + 1 , k, v)); mp.put(k, freqmp.get(freq + 1 ).getFirst()); } void set (int k, int v) { if (mp.containsKey(k)) { update(mp.get(k), k, v); return ; } if (size == 0 ) { int oldKey = freqmp.get(minFreq).getLast().key; freqmp.get(minFreq).removeLast(); if (freqmp.get(minFreq).isEmpty()) freqmp.remove(minFreq); mp.remove(oldKey); } else size--; minFreq = 1 ; if (!freqmp.containsKey(1 )) freqmp.put(1 , new LinkedList <N>()); freqmp.get(1 ).addFirst(new N (1 , k, v)); mp.put(k, freqmp.get(1 ).getFirst()); } int get (int k) { int res = -1 ; if (mp.containsKey(k)) { N n = mp.get(k); res = n.val; update(n, k, res); } return res; } public int [] LFU(int [][] operators, int k) { this .size = k; int len = (int ) Arrays.stream(operators) .filter(x -> x[0 ] == 2 ) .count(); int [] res = new int [len]; for (int i = 0 , j = 0 ; i < operators.length; i++) { if (operators[i][0 ] == 1 ) { set(operators[i][1 ], operators[i][2 ]); } else { res[j++] = get(operators[i][1 ]); } } return res; } }