趁着5.1假期把牛客网的必刷的TOP101过一遍,额,题目量有点大,争取5天给刷完吧,哈哈,加油啦。再用雷布斯的那句话来激励自己吧:努力了那么多年,回头一望,几乎全是漫长的挫折和煎熬。对于大多数人的一生来说,顺风顺水只是偶尔,挫折、不堪、焦虑和迷茫才是主旋律。
一、链表篇
1.1、反转链表
题目链接:反转链表_牛客题霸_牛客网
思路:构造一个新链表,每次把原链表的一个节点摘下来作为新链表的头节点,即可实现反转。
Java版:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode ReverseList(ListNode head) {
//双链表法实现链表反转,每次摘掉的链表,使其成为新链表的头节点
ListNode newHead = null ;
while(head != null){
//把头节点摘下来,为新链表的头节点
ListNode tmp = head.next ;
head.next = newHead ;
newHead = head ;
//继续向后走
head = tmp ;
}
return newHead ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @return ListNode类
#
class Solution:
def ReverseList(self , head: ListNode) -> ListNode:
# write code here
if not head:
return None
newHead = ListNode(head.val)
head = head.next
while head:
tmp = head.next
head.next = newHead
newHead = head
head = tmp
return newHead
1.2、链表内指定区间的反转
题目链接:链表内指定区间反转_牛客题霸_牛客网
思路:构造一个带头节点的新链表,遍历到指定m位置,每次修改三次指针,最后去掉新链表的头节点就是反转后的链表。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
public ListNode reverseBetween (ListNode head, int m, int n) {
// write code here
//指定区间内反转链表,只需要在原来的基础之上找到相应位置开始反转
ListNode newH = new ListNode(-1) ;
newH.next = head ;
ListNode pre = newH ;
ListNode cur = head ;
for(int i=1; i<m; i++){
pre = cur ;
cur = cur.next ;
}
//每次摘掉一个节点,放到当前节点的前面
for(int i=m; i<n; i++){
ListNode tmp = cur.next ;
cur.next = tmp.next ; //让2指向4
tmp.next = pre.next ; //让3指向2
pre.next = tmp ; //将1指向3
}
return newH.next ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @param m int整型
# @param n int整型
# @return ListNode类
#
class Solution:
def reverseBetween(self , head: ListNode, m: int, n: int) -> ListNode:
# write code here
newH = ListNode(-1)
newH.next = head
pre = newH
cur = head
for i in range(1,m):
pre = cur
cur = cur.next
for i in range(m,n):
tmp = cur.next
cur.next = tmp.next
tmp.next = pre.next
pre.next = tmp
return newH.next
1.3、链表中的节点每k个一组翻转
题目链接:链表中的节点每k个一组翻转_牛客题霸_牛客网
思路:借助栈实现,每次k个节点入栈,出栈后拼接到一起,不满足k个的则直接拼接即可。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode reverseKGroup (ListNode head, int k) {
// write code here
//借助栈实现链表的反转,每次k个节点入栈,节点出栈反转
ListNode res = new ListNode(1) ;
ListNode p = res ;
while(true){
Stack<ListNode> stack = new Stack<>() ;
int cnt = k ;
ListNode tmp = head ;
while(cnt!=0 && head != null){
stack.push(head) ;
head = head.next ;
cnt -- ;
}
if(cnt != 0){
p.next = tmp ;
break ;
}
while(!stack.isEmpty()){
p.next = stack.pop() ;
p = p.next ;
}
}
return res.next ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @param k int整型
# @return ListNode类
#
class Solution:
def reverseKGroup(self , head: ListNode, k: int) -> ListNode:
# write code here
newHead = ListNode(-1)
p = newHead
while True:
stack = []
cnt = k
tmp = head
while cnt and head:
stack.append(head)
head = head.next
cnt = cnt - 1
if cnt:
p.next = tmp
break
while stack:
p.next = stack.pop()
p = p.next
return newHead.next
1.4、合并两个排序的链表
题目链接:合并两个排序的链表_牛客题霸_牛客网
思路:迭代法和递归法都可以实现,这里构建一个新的空链表,遍历两个链表,依次将小的值拼接上去就可以了。
Java版:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
//迭代法
ListNode node = new ListNode(-1) ;
ListNode cur = node ;
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 ;
}
cur.next = list1 == null ? list2 : list1 ;
return node.next ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param pHead1 ListNode类
# @param pHead2 ListNode类
# @return ListNode类
#
class Solution:
def Merge(self , pHead1: ListNode, pHead2: ListNode) -> ListNode:
# write code here
h = ListNode(0)
p = h
while pHead1 and pHead2:
if pHead1.val <= pHead2.val:
p.next = pHead1
pHead1 = pHead1.next
else:
p.next = pHead2
pHead2 = pHead2.next
p = p.next
if pHead1:
p.next = pHead1
if pHead2:
p.next = pHead2
return h.next
1.5、判断链表是否有环
题目链接:判断链表中是否有环_牛客题霸_牛客网
思路:快慢指针,需要注意是节点相同,而不是仅仅是节点的值相同,还有循环条件要设置好。
Java版本:
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
//快慢指针
if(head == null || head.next == null){
return false ;
}
ListNode fast = head ;
ListNode slow = head ;
while(fast != null && fast.next != null){
fast = fast.next.next ;
slow = slow.next ;
if(slow == fast){
return true ;
}
}
return false ;
}
}
Python版本:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
#
# @param head ListNode类
# @return bool布尔型
#
class Solution:
def hasCycle(self , head: ListNode) -> bool:
fast = head
slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast:
return True
return False
1.6、链表中环的入口结点
题目链接:链表中环的入口结点_牛客题霸_牛客网
思路:快慢指针,相遇后,相遇节点距离环入口点的距离和起点距离入口节点的距离相等。
Java版:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode fast = pHead ;
ListNode slow = pHead ;
if(pHead == null || pHead.next == null){
return null ;
}
while(fast != null && fast.next != null){
fast = fast.next.next ;
slow = slow.next ;
if(slow == fast){
fast = pHead ;
break ;
}
if(slow == null || fast == null){
return null ;
}
}
while(slow != fast){
slow = slow.next ;
fast = fast.next ;
}
return fast ;
}
}
Python版:
from contextlib import nullcontext
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
slow = pHead
fast = pHead
if not pHead or not pHead.next:
return None
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
fast = pHead
break
if not slow or not fast:
return None
while fast != slow:
fast = fast.next
slow = slow.next
return fast
1.7、链表中倒数最后k个结点
题目链接:链表中倒数最后k个结点_牛客题霸_牛客网
思路:计算链表长度len,然后向后遍历,找到len-k开头的链表就是倒数最后k个节点。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pHead ListNode类
* @param k int整型
* @return ListNode类
*/
public ListNode FindKthToTail (ListNode pHead, int k) {
// write code here
int len = 0 ;
ListNode cur = pHead ;
while(cur != null){
cur = cur.next ;
len ++ ;
}
if(k>len){
return null ;
}
for(int i=0; i<len-k; i++){
pHead = pHead.next ;
}
return pHead ;
}
}
Python版:
from contextlib import nullcontext
from pickle import NONE
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param pHead ListNode类
# @param k int整型
# @return ListNode类
#
class Solution:
def FindKthToTail(self , pHead: ListNode, k: int) -> ListNode:
# write code here
l = 0
cur = pHead
while cur:
cur = cur.next
l = l + 1
j = l - k
if j < 0 :
return None
while j > 0:
pHead = pHead.next
j = j - 1
return pHead
1.8、删除链表的倒数第n个节点
题目链接:删除链表的倒数第n个节点_牛客题霸_牛客网
思路:计算链表长度,然后修改链表指针删除第n个节点,如果是第一个节点,则直接返回去除头节点的链表。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param n int整型
* @return ListNode类
*/
public ListNode removeNthFromEnd (ListNode head, int n) {
// write code here
ListNode res = head ;
int len = 0 ;
ListNode tmp = res ;
ListNode cur = head ;
while(cur != null){
cur = cur.next ;
len ++ ;
}
int j = len - n ;
if(j==0){
return res.next ;
}
while(j>0){
tmp = head ;
head = head.next ;
j -- ;
}
tmp.next = tmp.next.next ;
return res ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @param n int整型
# @return ListNode类
#
class Solution:
def removeNthFromEnd(self , head: ListNode, n: int) -> ListNode:
# write code here
l = 0
cur = head
tmp = res = head
while cur:
cur = cur.next
l = l + 1
j = l - n
if j == 0 :
return head.next
while j > 0 :
tmp = head
head = head.next
j = j - 1
tmp.next = tmp.next.next
return res
1.9、两个链表的第一个公共节点
题目链接:两个链表的第一个公共结点_牛客题霸_牛客网
思路:长的链表的长度-短链表长度=n,则长的先跑n,然后长短链表一起跑,并判断是否有公共节点。
Java版:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
int len1 = 0, len2 = 0 ;
ListNode p1 = pHead1 ;
ListNode p2 = pHead2 ;
while(p1 != null){
p1 = p1.next ;
len1 ++ ;
}
while(p2 != null){
p2 = p2.next ;
len2 ++ ;
}
int dur = len1 - len2 >= 0 ? len1 - len2 : len2 - len1 ;
if(len1 >= len2){
for(int i=0; i<dur; i++){
pHead1 = pHead1.next ;
}
}else{
for(int i=0; i<dur; i++){
pHead2 = pHead2.next ;
}
}
while(pHead1 != null && pHead2 != null){
if(pHead1 == pHead2){
return pHead1 ;
}
pHead1 = pHead1.next ;
pHead2 = pHead2.next ;
}
return null ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
#
# @param pHead1 ListNode类
# @param pHead2 ListNode类
# @return ListNode类
#
class Solution:
def FindFirstCommonNode(self , pHead1 , pHead2 ):
# write code here
p1 = pHead1
p2 = pHead2
l1 = l2 = 0
while p1:
p1 = p1.next
l1 = l1 + 1
while p2:
p2 = p2.next
l2 = l2 + 1
if(l1 >= l2):
for i in range(0,l1-l2):
pHead1 = pHead1.next
else:
for i in range(0,l2-l1):
pHead2 = pHead2.next
while(pHead1 and pHead2):
if pHead1 == pHead2:
return pHead1
pHead1 = pHead1.next
pHead2 = pHead2.next
return None
1.10、链表相加(二)
题目链接:链表相加(二)_牛客题霸_牛客网
思路:借助栈的后进先出的思想,依次累加元素,并拼接到新链表的头部。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head1 ListNode类
* @param head2 ListNode类
* @return ListNode类
*/
public ListNode addInList (ListNode head1, ListNode head2) {
// write code here
//借助栈的先进后出功能实现
Stack<ListNode> stack1 = new Stack<>() ;
Stack<ListNode> stack2 = new Stack<>() ;
ListNode h1 = head1 ;
ListNode h2 = head2 ;
ListNode p = null ;
while(h1 != null){
stack1.push(h1) ;
h1 = h1.next ;
}
while(h2 != null){
stack2.push(h2) ;
h2 = h2.next ;
}
int v = 0 ;
while(!stack1.isEmpty() || !stack2.isEmpty()){
if(!stack1.isEmpty()){
v += stack1.pop().val ;
}
if(!stack2.isEmpty()){
v += stack2.pop().val ;
}
ListNode node = new ListNode(v%10) ;
node.next = p ;
p = node ;
v = v/10 ;
}
if(v > 0){
ListNode node1 = new ListNode(v) ;
node1.next = p ;
p = node1 ;
}
return p ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head1 ListNode类
# @param head2 ListNode类
# @return ListNode类
#
class Solution:
def addInList(self , head1: ListNode, head2: ListNode) -> ListNode:
# write code here
stack1 = []
stack2 = []
p1 = ListNode(0)
p = p1.next
while head1:
stack1.append(head1)
head1 = head1.next
while head2:
stack2.append(head2)
head2 = head2.next
cnt = 0
while stack1 or stack2:
if stack1 :
cnt = cnt + stack1.pop().val
if stack2:
cnt = cnt + stack2.pop().val
tmp = ListNode(cnt%10)
tmp.next = p
p = tmp
cnt = cnt // 10
if cnt :
tmp1 = ListNode(cnt)
tmp1.next = p
p = tmp1
return p
1.11、单链表的排序
题目链接:单链表的排序_牛客题霸_牛客网
思路:用集合给元素排序,然后依次改变链表元素的值就可以了。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类 the head node
* @return ListNode类
*/
public ListNode sortInList (ListNode head) {
// write code here
List<Integer> list = new ArrayList<>() ;
ListNode h = head ;
ListNode p = h ;
while(h != null){
list.add(h.val) ;
h = h.next ;
}
Collections.sort(list) ;
for(int i=0; i<list.size(); i++){
head.val = list.get(i) ;
head = head.next ;
}
return p ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类 the head node
# @return ListNode类
#
class Solution:
def sortInList(self , head: ListNode) -> ListNode:
# write code here
lst = []
p = h = head
while h:
lst.append(h.val)
h = h.next
lst.sort()
for l in lst:
head.val = l
head = head.next
return p
1.12、判断一个链表是否为回文结构
题目链接:判断一个链表是否为回文结构_牛客题霸_牛客网
思路:借助栈,依次比对即可。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类 the head
* @return bool布尔型
*/
public boolean isPail (ListNode head) {
// write code here
Stack<ListNode> stack = new Stack<>() ;
ListNode h = head ;
while(h!=null){
stack.push(h) ;
h = h.next ;
}
while(!stack.isEmpty()){
ListNode s = stack.pop() ;
if(s.val != head.val){
return false ;
}
head = head.next ;
}
return true ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类 the head
# @return bool布尔型
#
class Solution:
def isPail(self , head: ListNode) -> bool:
# write code here
stack = []
h = head
while h:
stack.append(h)
h = h.next
while stack:
if stack.pop().val != head.val:
return False
head = head.next
return True
1.13、 链表的奇偶重排
题目链接:链表的奇偶重排_牛客题霸_牛客网
思路:List集合记录奇数和偶数位置的数字,然后依次更改原链表的数值即可。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode oddEvenList (ListNode head) {
// write code here
int cnt = 1 ;
ListNode p = head ;
ListNode tmp = head ;
List<Integer> odd = new ArrayList<>() ;
List<Integer> even = new ArrayList<>() ;
while(p != null){
if(cnt%2==1){
odd.add(p.val) ;
}else{
even.add(p.val) ;
}
cnt ++ ;
p = p.next ;
}
int i = 0, j = 0 ;
while(tmp != null){
if(i < odd.size()){
tmp.val = odd.get(i) ;
i ++ ;
}else{
tmp.val = even.get(j) ;
j ++ ;
}
tmp = tmp.next ;
}
return head ;
}
}
Python版:
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head ListNode类
# @return ListNode类
#
class Solution:
def oddEvenList(self , head: ListNode) -> ListNode:
# write code here
lst1 = []
lst2 = []
s = 1
p = h = head
while p:
if s%2==1:
lst1.append(p.val)
else:
lst2.append(p.val)
s = s + 1
p = p.next
i = j = 0
while head:
if i < len(lst1):
head.val = lst1[i]
i = i + 1
else:
head.val = lst2[j]
j = j + 1
head = head.next
return h
1.14、删除有序链表中重复的元素-I
题目链接:删除有序链表中重复的元素-I_牛客题霸_牛客网
思路:借助队列实现,删除重复元素。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode deleteDuplicates (ListNode head) {
// write code here
Queue<Integer> queue = new LinkedList<>() ;
ListNode p = head ;
ListNode cur = head ;
while(p != null){
queue.offer(p.val) ;
p = p.next ;
}
while(cur != null){
int v = queue.poll() ;
if(!queue.contains(v)){
cur.val = v ;
cur = cur.next ;
}else{
cur.next = cur.next.next ;
}
}
return head ;
}
}
1.15、删除有序链表中重复的元素-II
题目链接:删除有序链表中重复的元素-II_牛客题霸_牛客网
思路:用map记录,不过在之前next,应该在最后再去掉头元素。
Java版:
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode deleteDuplicates (ListNode head) {
// write code here
ListNode p = head ;
ListNode h = new ListNode(-1);
ListNode newH = h ;
Map<Integer,Integer> map = new TreeMap<>() ;
while(p != null){
if(map.containsKey(p.val)){
map.put(p.val,map.get(p.val)+1) ;
}else{
map.put(p.val, 1) ;
}
p = p.next ;
}
while(head != null){
if(map.get(head.val) == 1){
h.next = new ListNode(head.val) ;
h = h.next ;
}
head = head.next ;
}
return newH.next ;
}
}
1.16、合并k个已排序的链表
题目链接:合并k个已排序的链表_牛客题霸_牛客网
思路:借助辅助数组,获取所有链表元素并排序,然后拼接到一起就可以了。
Java版:
import java.util.*;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
ListNode p = new ListNode(-1) ;
ListNode h = p ;
ArrayList<Integer> lst = new ArrayList<>() ;
for(ListNode tmp : lists){
while(tmp != null){
lst.add(tmp.val) ;
tmp = tmp.next ;
}
}
Collections.sort(lst) ;
for(Integer v : lst){
p.next = new ListNode(v) ;
p = p.next ;
}
return h.next ;
}
}
Python版:
from re import L
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param lists ListNode类一维数组
# @return ListNode类
#
class Solution:
def mergeKLists(self , lists: List[ListNode]) -> ListNode:
# write code here
lst = []
p = ListNode(-1)
h = p
for list in lists:
while list:
lst.append(list.val)
list = list.next
lst.sort()
for v in lst:
p.next = ListNode(v)
p = p.next
return h.next