刷题挑战链接 
链表 
题号 
题目名称 
核心思路 
时间复杂度 
空间复杂度 
代码亮点 
牛客原题链接 
 
 
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 
 
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 
 
双指针 
 
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 
 
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 
 
归并排序 
 
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 
 
递归 
 
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 
 
层序遍历 + 回文/对称 
 
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 
 
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 
 
排序 
 
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 
 
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 
 
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 
 
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 
 
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 
 
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 
 
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. 纵向扫描(逐位比较) 
O(S) / O(S·log L) 
O(1) / O(1) 
纵向扫描思路直观;二分优化适合前缀较短场景;空间均为 O(1) 
🔗 直达  
BM85 验证IP地址 
1. 条件枚举逐段检查 
O(1) 
O(1) 
枚举法逻辑清晰易调试;正则法代码简洁但可读性稍差 
🔗 直达  
BM86 大数加法 
1. 两次翻转+进位 
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;                                       } }