链表高频面试算法题
1、两个链表的第一个公共子结点
题目:牛客JZ52
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。
方法一:哈希和集合。先将一个链表元素全部存到Map里,然后一边遍历第二个链表,一边检测Hash中是否存在当前结点,如果有交点,则一定能检测出来。
Java代码:
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
Set<ListNode> set = new HashSet<>();
while(pHead1 != null){
set.add(pHead1);
pHead1 = pHead1.next;
}
while(pHead2 != null){
if(set.contains(pHead2)){
return pHead2;
}
pHead2 = pHead2.next;
}
return null;
}
Python代码:
def FindFirstCommonNode(self , pHead1 , pHead2):
s = set()
p = pHead1
q = pHead2
while(p):
s.add(p)
p = p.next
while(q):
if q in s:
return q
q = q.next
return None
由于C语言基础包里没有定义集合类型,如果用集合需要先自己构建一个,或者引入外部包,因此不提供代码。
方法二:使用栈。分别将两个链表的结点压入两个栈,然后分别出栈,如果相等就继续出栈,一直找到最晚出栈的那一组。这种方式需要两个O(n)的空间,不是最好。
Java代码:
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2){
Stack<ListNode> stackA = new Stack<>();
Stack<ListNode> stackB = new Stack<>();
while(pHead1 != null){
stackA.push(pHead1);
pHead1 = pHead1.next;
}
while(pHead2 != null){
stackB.push(pHead2);
pHead2 = pHead2.next;
}
ListNode preNode = null;
while(stackA.size() > 0 && stackB.size() > 0){
if(stackA.peek() == stackB.peek()){ //stack.peek()只能返回栈顶有元素,不能删除栈顶元素
preNode = stackA.pop(); //stack.pop()可以返回栈顶元素
stackB.pop(); //stack.pop()是出栈的意思,也就是删除栈顶元素
}
else{
break;
}
}
return preNode;
}
Python代码:
def FindFirstCommonNode(self , pHead1 , pHead2):
s1, s2 = [], []
p, q = pHead1, pHead2
while p:
s1.append(p)
p = p.next
while q:
s2.append(q)
q = q.next
ans = None
i, j = len(s1) - 1,len(s2) - 1
while i >= 0 and j >= 0 and s1[i] == s2[j]:
ans = s1[i]
i, j = i - 1, j - 1
return ans
由于C语言基础包里没有提供栈类型,如果用栈需要先自己构建一个,或者引入外部包,因此不提供代码。
方法三:拼接两个字符串(双指针法)。题中两个链表分别为{1,2,3,6,7}和{4,5,6,7}。有两种形式拼接两个链表:①:1-2-3-6-7-4-5-6-7;②4-5-6-7-1-2-3-4-6-7。
我们发现拼接从最后的6开始,后面的结点一样了,6 就是要找的结点,所以可以通过拼接的方式来寻找交点。
因此遍历拼接后的两个链表就能找到交点。
但是建立新的链表太浪费空间了,我们只需要在每个链表访问完之后,调整到下一链表的表头继续访问就行了。(这操作是真的牛了)
但是个人感觉这个拼接链表不正确,因为两个链表的6结点是一样的,真正拼接时应该会形成一个有环链表,此时两个链表的结点7不一样了,所以······不知道该怎么解释。
但又好在本题的解法不用拼接链表,只需要在每个链表访问之后,调整到下一链表的表头继续访问就行了。
Java代码:
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null){
return null;
}
ListNode p1 = pHead1;
ListNode p2 = pHead2;
while(p1 != p2){
p1 = p1.next;
p2 = p2.next;
//这个地方的if是很重要的,如果没有这个if,那么在两个链表没有交点时,上面的while就会陷入死循环
if(p1 != p2){
//一个链表访问完了就跳到另外一个链表继续访问
if(p1 == null){
p1 = pHead2;
}
//一个链表访问完了就跳到另外一个链表继续访问
if(p2 == null){
p2 = pHead1;
}
}
}
return p1;
}
}
Python代码:
def FindFirstCommonNode(self , pHead1 , pHead2):
node1 = pHead1
node2 = pHead2
while node1 != node2:
node1 = node1.next if node1 else pHead2
node2 = node2.next if node2 else pHead1
return node1
C语言代码:
struct ListNode* FindFirstCommonNode(struct ListNode* pHead1, struct ListNode* pHead2 ) {
if(pHead1 == NULL || pHead2 == NULL){
return NULL;
}
struct ListNode* p1 = pHead1;
struct ListNode* p2 = pHead2;
while(p1 != p2){
p1 = p1->next;
p2 = p2->next;
if(p1 != p2){
//一个链表访问完了就跳到另外一个链表继续访问
if(p1 == NULL){
p1 = pHead2;
}
if(p2 == NULL){
p2 = pHead1;
}
}
}
return p1;
}
方法四:差和双指针。假如公共子结点一定存在第一遍历,就是两个链表都不为空的意思,假设La长度为L1,Lb长度为L2。则 |L2 -L1| 就是两链表长度的差值。第二轮遍历,长的先走 |L2-L1| ,然后两个链表同时向前走,结点一样的时候就是公共结点了。
Java代码:
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
if(pHead1 == null || pHead2 == null){
return null;
}
ListNode current1 = pHead1;
ListNode current2 = pHead2;
int l1 = 0;
int l2 = 0;
while(current1 != null){
current1 = current1.next;
l1 ++;
}
while(current2 != null){
current2 = current2.next;
l2 ++;
}
current1 = pHead1;
current2 = pHead2;
int sub = l1 > l2 ? l1 - l2 : l2 - l1;
if(l1 > l2){
int a = 0;
while(a < sub){
current1 = current1.next;
a ++;
}
}
else{
int a = 0;
while(a < sub){
current2 = current2.next;
a ++;
}
}
while(current1 != current2){
current1 = current1.next;
current2 = current2.next;
}
return current1;
}
Python代码:
def FindFirstCommonNode(self , pHead1 , pHead2):
s1 = 0
s2 = 0
p = pHead1
q = pHead2
while p:
p = p.next
s1 += 1
while q:
q = q.next
s2 += 1
p = pHead1
q = pHead2
#以下两个for循环只会执行一个
for i in range(s1 - s2):
p = p.next
for i in range(s2 - s1):
q = q.next
while p and q and p != q:
p = p.next
q = q.next
return p
C语言代码:
struct ListNode* FindFirstCommonNode(struct ListNode* pHead1,
struct ListNode* pHead2 ) {
if (pHead1 == NULL || pHead2 == NULL) {
return NULL;
}
struct ListNode* current1 = pHead1;
struct ListNode* current2 = pHead2;
int l1 = 0;
int l2 = 0;
while (current1 != NULL) {
current1 = current1->next;
l1 ++;
}
while (current2 != NULL) {
current2 = current2->next;
l2 ++;
}
current1 = pHead1;
current2 = pHead2;
int sub = l1 > l2 ? l1 - l2 : l2 - l1;
//长的先走sub步
if (l1 > l2) {
int a = 0;
while (a < sub) {
current1 = current1->next;
a ++;
}
}
else {
int a = 0;
while (a < sub) {
current2 = current2->next;
a ++;
}
}
//同时遍历两个链表
while(current1 != current2){
current1 = current1->next;
current2 = current2->next;
}
return current1;
}
2、判断链表是否为回文序列
题目:LeetCode234
给你一个单链表的头节点 head,请你判断该链表是否为回文链表。如果是,返回 true;否则,返回 false。
示例:
输入:head = [1,2,2,1]
输出:true
本题方法有很多,简单举例。
方法一:将链表元素都赋值到数组中,然后可以从数组两端向中间对比。这种方法会被视为逃避链表,面试不能这么干。
注意:本方法只有Python核心代码。
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
cur, length = head, 0
result = []
while cur is not None:
length += 1
result.append(cur.val)
cur = cur.next
#运用双指针,分别从前和从后遍历链表
left, right = 0, length - 1
while left < right:
if result[left] != result[right]:
return False
left += 1
right -= 1
return True
方法二:将链表元素全部压栈,然后一边出栈,一边重新遍历链表,一边比较两者元素值,只要有一个元素值,那就不是回文序列。
注意:本方法只有Java核心代码。
public boolean isPalindrome(ListNode head) {
ListNode temp = head;
//创建一个栈
Stack<Integer> stack = new Stack();
//把链表结点的值存放到栈中
while(temp != null){
stack.push(temp.val);
temp = temp.next;
}
while(head != null){
if(head.val != stack.pop())
return false;
head = head.next;
}
return true;
}
由于C语言基础包里没有提供栈类型,如果用栈需要先自己构建一个,或者引入外部包,因此不提供代码。
3、合并有序链表(合并两个有序链表)
题目:LeetCode21
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
方法:新建一个链表,然后分别遍历两个链表,每次都选择最小的结点接到新链表上,最后排完。最优美的代码写法如下:
Java代码:
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
//创建一个新链表
ListNode newHead = new ListNode(-1);
ListNode res = newHead;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
newHead.next = list1;
list1 = list1.next;
}
else if(list1.val > list2.val){
newHead.next = list2;
list2 = list2.next;
}
newHead = newHead.next;
}
//最多只有一个还未被合并完,直接接上去就行了,这是链表合并比数组合并方便的地方。
//这方法还是挺厉害的。
newHead.next = list1 == null? list2:list1;
return res.next;
}
Python代码:
def mergeTwoLists(self, list1, list2):
p = ListNode(0)
phead = p
while list1 and list2:
if list1.val <= list2.val:
p.next = list1
list1 = list1.next
else:
p.next = list2
list2 = list2.next
p = p.next
if list1 is not None:
p.next = list1
else:
p.next = list2
return phead.next
C语言代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
//这种新建一个结点是不需要指出结点的val和next的呀
struct ListNode* prehead = (struct ListNode* )malloc(sizeof(struct ListNode));
struct ListNode* prev = prehead;
while(list1 != NULL && list2 != NULL){
if(list1->val <= list2->val){
prev->next = list1;
list1 = list1->next;
}
else{
prev->next = list2;
list2 = list2->next;
}
prev = prev->next;
}
prev->next = list1 == NULL ? list2 : list1;
return prehead->next;
}
4、合并有序链表(合并K个升序链表)
题目:LeetCode23
给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 :
输入:lists = [ [1,4,5], [1,3,4], [2,6] ]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
方法:先将前两个合并,之后再将后面的逐步合并进来,这样的好处是只要将两个合并的写清楚,合并K个就容易很多。
Java代码:
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
//创建一个新结点
ListNode newHead = new ListNode(-1);
ListNode res = newHead;
while(list1 != null && list2 != null){
if(list1.val <= list2.val){
newHead.next = list1;
list1 = list1.next;
}
else if(list1.val > list2.val){
newHead.next = list2;
list2 = list2.next;
}
newHead = newHead.next;
}
newHead.next = list1 == null? list2:list1;
return res.next;
}
public ListNode mergeKLists(ListNode[] lists) {
ListNode res = null;
for(ListNode list:lists){
res = mergeTwoLists(res, list);
}
return res;
}
Python代码:
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
def mergeTwoLists(a, b):
merge = ListNode(-1)
head = merge
while a and b:
if a.val >= b.val:
head.next = b
b = b.next
else:
head.next = a
a = a.next
head = head.next
head.next = a if a else b
return merge.next
if len(lists) == 0:
return None
res = None
for i in range(0, len(lists)):
res = mergeTwoLists(res, lists[i])
return res
C语言代码:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead->val = -1;
newHead->next = NULL;
struct ListNode* res = newHead;
while(list1 != NULL || list2 != NULL){
if(list1 != NULL && list2 != NULL){
if(list1->val < list2->val){
newHead->next = list1;
newHead = newHead->next;
list1 = list1->next;
}
else if(list1->val > list2->val){
newHead->next = list2;
newHead = newHead->next;
list2 = list2->next;
}
else{
newHead->next = list1;
newHead = newHead->next;
list1 = list1->next;
newHead->next = list2;
newHead = newHead->next;
list2 = list2->next;
}
}
else if(list1 == NULL && list2 != NULL){
newHead->next = list2;
list2 = list2->next;
newHead = newHead->next;
}
else if(list1 != NULL && list2 == NULL){
newHead->next = list1;
list1 = list1->next;
newHead = newHead->next;
}
}
return res->next;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
struct ListNode* res = NULL;
for(int i = 0; i < listsSize; i ++){
res = mergeTwoLists(res, lists[i]);
}
return res;
}
5、合并有序链表(一道好题)
题目:LeetCode1669
给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。请你将 list1 中下标从 a 到 b 的全部节点都删除,并将list2 接在被删除节点的位置。最后返回结果链表的头指针。
下图中蓝色边和节点展示了操作后的结果:
方法:遍历第一个链表,找到链表1保留部分的尾结点和头结点;
遍历第二个链表,找到链表2的尾结点,将两个链表连接起来。
Java代码:
public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
ListNode pre1 = list1, post1 = list1, post2 = list2;
int i = 0, j = 0;
for(i = 0; i < a - 1; i ++){
pre1 = pre1.next;
}
for(j = 0; j < b + 1; j ++){
post1 = post1.next;
}
pre1.next = post2;
while(post2.next != null){
post2 = post2.next;
}
post2.next = post1;
return list1;
}
Python代码:
def mergeInBetween(self, list1, a, b, list2):
#dummy = ListNode(0)
#dummy.next = list1
tmp1 = list1
tmp2 = list1
l1 = 0
l2 = 0
while l1 < a - 1:
tmp1 = tmp1.next
l1 += 1
while l2 < b + 1:
tmp2 = tmp2.next
l2 += 1
tmp1.next = list2
while list2.next:
list2 = list2.next
list2.next = tmp2
return list1
C语言代码:
struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2){
struct ListNode* pre1 = list1;
struct ListNode* post1 = list1;
struct ListNode* post2 = list2;
int i = 0, j = 0;
for(i = 0; i < a - 1; i ++){ //下列代码执行了(a - 1)次
pre1 = pre1->next;
}
for(j = 0; j < b + 1; j ++){
post1 = post1->next;
}
pre1->next = post2;
while(post2->next != NULL){
post2 = post2->next;
}
post2->next = post1;
return list1;
}
6、寻找中间结点
题目:LeetCode876
给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
方法:快慢指针法。fast指针一次走两步,slow指针一次走一步,当fast指针到达链表尾部时,slow必然位于中间。
Java代码:
class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
Python代码:
class Solution(object):
def middleNode(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
#if head is None:
# return None
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
Python代码(含本地编辑器测试):
class LinkNode(object):
def __init__(self, val = None, next = None):
self.val = val
self.next = next
def init_list(nums):
tem_node = LinkNode()
tem = LinkNode()
for i in nums:
if tem_node.val == None:
tem_node.val = i
tem = tem_node
else:
tem_node.next = LinkNode(i)
tem_node = tem_node.next
return tem
class MiddleNode():
def middleNode(self, head):
if head is None:
return None
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
return slow
if __name__ == "__main__":
nums = [0, 0, 3, 4, 5, 6]
list = init_list(nums)
middleNode = MiddleNode()
node = middleNode.middleNode(list)
print(node.val)
C++代码:
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast -> next != NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
7、寻找倒数第K个元素
题目:牛客HJ51
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
正常返回倒数第k个结点指针,异常返回空指针。
方法:快慢指针法。先将fast向后遍历到第k+1个结点,slow仍然指向链表的第一个结点,此时指针fast与slow二者之间刚好间隔k个结点。之后两个指针同步向后走,当fast走到链表的尾部空结点时,slow指针刚好指向链表的倒数第k个结点。
Java代码:
//咳咳,以下是acm模式下的代码
import java.util.Scanner; // 头文件
class ListNode{
int val;
ListNode next;
}
// 注意类名必须为 Main, 不要有任何 package xxx 信息,定义的不是结构体,是类,要加public
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in); //开头这三句话都是原来就有的,感觉有点陌生
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNext()) { // 注意 while 处理多个 case
ListNode node = new ListNode();
node.next = null;
ListNode n = node;
int N = in.nextInt();
for(int i = 0; i < N; i ++){
ListNode p = new ListNode();
int x = in.nextInt();
p.val = x;
node.next = p;
node = node.next; //也可以写成node = p;
}
int k = in.nextInt();
ListNode kthNode = getKthNode(n, k);
System.out.println(kthNode.val);
}
}
public static ListNode getKthNode(ListNode n, int k){
ListNode fast = n;
ListNode slow = n;
for(int i = 0; i < k; i ++){
if(fast != null)
fast = fast.next;
else
return null;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
return slow;
}
}
Python代码:
#咳咳,以下是acm模式下的代码
class ListNode(object):
def __init__(self, val = None, next = None):
self.val = val
self.next = next
def GetKthFromTail(head: ListNode, k):
fast = head
slow = head
for i in range(k): #不太懂,这样就是执行了k次嘛
if fast:
fast = fast.next
else:
return None
while fast:
fast = fast.next
slow = slow.next
return slow
if __name__ == "__main__":
while True: #直接这么写就可以处理多种情况了呀,python还真是简单
try:
N = int(input())
ls = input().split()
k = int(input())
head = ListNode(ls[0])
cur = head
for i in range(1, N):
head.next = ListNode(ls[i])
head = head.next
if k:
p_Kth = GetKthFromTail(cur, k)
if p_Kth:
print(p_Kth.val)
else:
print('0')
else:
print('0')
except:
break
C++代码:
//咳咳,以下是acm模式下的代码
#include<iostream>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode(int x): val(x), next(NULL){}
};
ListNode* FindKthToTail(ListNode* pHead, int k){
ListNode* fast = pHead;
ListNode* slow = pHead;
for(int i = 0; i < k; i ++){ //0~k就是执行了k次
if(fast != NULL)
fast = fast->next;
else
return slow = NULL;//链表长度小于k的时候,返回空链表
}
while(fast != NULL){ //fast最后在整个链表的后一个的位置
fast = fast->next;
slow = slow->next;
}
return slow;
}
int main(){
int n;
while(cin >> n){
int val;
cin >> val;
ListNode* head = new ListNode(val); //这样就新建了一个结点,比c语言新建一个结点简洁一些
ListNode* p = head;
for(int i = 1; i < n; i++){
cin >> val;
ListNode* a = new ListNode(val);
p->next = a;
p = p->next;
}
int k;
cin >> k;
if(k == 0)
cout << "false" << endl;
else{
p = FindKthToTail(head, k);
if(p != NULL)
cout << p->val << endl;
}
}
return 0;
}
8、旋转链表
题目:LeetCode61
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
方法一:快慢指针法。
①有可能k大于链表长度,所以首先获取一下链表长度冷,然后k = k % len,如果k == 0,则不用旋转,直接返回头结点。否则:
②先将fast向后遍历到第k+1个结点,slow仍然指向链表的第一个结点,此时指针fast与slow二者之间刚好间隔k个结点;
③慢指针和快指针一起走;
④快指针走到链表尾部时,慢指针所在位置刚好是要断开的地方。把快指针指向的结点连接到原链表头部,慢指针指向的结点断开和下一结点的联系;
⑤返回结束时慢指针指向的下一结点。
Java代码:
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null || k == 0){
return head;
}
//这里三个变量都指向链表头结点
ListNode temp = head;
ListNode fast = head;
ListNode slow = head;
//计算出链表的长度
int len = 0;
while(head != null){
head = head.next;
len ++;
}
if(k % len == 0){
return temp;
}
k = k % len;
while(k > 0){
k --;
fast = fast.next;
}
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
ListNode res = slow.next;
fast.next = temp;
slow.next = null;
return res;
}
}
Python代码:
class Solution(object):
def rotateRight(self, head, k):
if head is None or head.next is None:
return head
num = 0
basic_head = head
new_head = head
flag = head
while head.next:
head = head.next
num += 1
num += 1
k = k % num
if(k == 0):
return flag
else:
xx = num - k
for i in range(xx - 1):
basic_head = basic_head.next
temp = basic_head.next
basic_head.next = None
head.next = new_head
return temp
C语言代码:
struct ListNode* rotateRight(struct ListNode* head, int k) {
if(head == NULL || k == 0){
return head;
}
//这里三个变量都指向链表头结点
struct ListNode* temp = head;
struct ListNode* fast = head;
struct ListNode* slow = head;
//统计出链表的元素个数,完成之后head就变成null了
int len = 0;
while(head != NULL){
head = head->next;
len ++;
}
if(k % len == 0){
return temp;
}
k = k % len;
while(k > 0){
k --;
fast = fast->next;
}
while(fast->next != NULL){
fast = fast->next;
slow = slow->next;
}
struct ListNode* res = slow->next;
slow->next = NULL;
fast->next = temp;
return res;
}
方法二:我们要找倒数第K个,那么就是要找正数第Len-k+1个。因此可以先遍历一遍,计算出Len,然后直接通过计算得到需要走的步数,只会从头开始遍历,到第Len-k+1即可。同时也要通过取模来计算防止K越界。我们这里只看一下Python的实现:
Python代码(本地编辑器测试代码):
class LinkNode(object):
def __init__(self, val = None, next = None):
self.val = val
self.next = next
def init_list(nums):
tem_node = LinkNode()
tem = LinkNode()
for i in nums:
if tem_node.val == None:
tem_node.val = i
tem = tem_node
else:
tem_node.next = LinkNode(i)
tem_node = tem_node.next
return tem
class RotateRight:
def rotateRight(self, head, k):
if head is None or head.next is None:
return head
num = 0
basic_head = head
new_head = head
flag = head
while head.next:
head = head.next
num += 1
num += 1
k = k % num
if(k == 0):
return flag
else:
xx = num - k
for i in range(xx - 1):
basic_head = basic_head.next
temp = basic_head.next
basic_head.next = None
head.next = new_head
return temp
#打印链表
def print_list(head):
if not head or not head.next:
return []#空数组的意思
result = []
while head:
result.append(head.val)
head = head.next
return result
if __name__ == "__main__":
#先构造题目要求的链表
nums = [1, 2, 3, 4, 5]
k = int(input())
list = init_list(nums)
rotateRight = RotateRight()
flag = rotateRight.rotateRight(list,k)
print(print_list(flag))
9、删除特定结点
题目:LeetCode203
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
方法:①创建一个虚拟链表头dummyHead,使其next指向head;
②开始循环链表寻找目标元素,注意这里是通过cur.next.val来判断的;
③如果找到目标元素,就使用cur.next = cur.next.next;
④最后返回的时候要用dummyHead.next,而不是dummyHead。
Java代码:
public ListNode removeElements(ListNode head, int val) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = dummyHead;
while(cur.next != null){
if(cur.next.val == val)
cur.next = cur.next.next;
else
cur = cur.next;
}
return dummyHead.next;
}
Python代码:
def removeElements(self, head, val):
while head and head.val == val:
head = head.next
if head is None:
return head
node = head
while node.next:
if node.next.val == val:
node.next = node.next.next
else:
node = node.next
return head
C语言代码:
struct ListNode* removeElements(struct ListNode* head, int val) {
struct ListNode* dummyHead = (struct ListNode* )malloc(sizeof(struct ListNode));
dummyHead->val = 0;
dummyHead->next = head;
struct ListNode* cur = dummyHead;
while(cur->next != NULL){
if(cur->next->val == val){
struct ListNode* temp = cur->next;
cur->next = cur->next->next;
free(temp);
}
else
cur = cur->next;
}
return dummyHead->next;
}
Python代码(本地编辑器测试代码):
class ListNode(object):
def __init__(self, val = None, next = None):
self.val = val
self.next = next
def init_list(nums):
tem_node = ListNode()
tem = ListNode()
for i in nums:
if tem_node.val == None:
tem_node.val = i
tem = tem_node
else:
tem_node.next = ListNode(i)
tem_node = tem_node.next
return tem
class RemoveElements:
def removeElements(self, head, val):
while head and head.val == val:
head = head.next
if head is None:
return head
node = head
while node.next:
if node.next.val == val:
node.next = node.next.next
else:
node = node.next
return head
def print_list(head):
if not head or not head.next:
return []
result = []
while head:
result.append(head.val)
head = head.next
return result
if __name__ == "__main__":
nums = [1, 2, 3, 4, 5, 6]
n = int(input())
list = init_list(nums)
removeElements = RemoveElements()
flag = removeElements.removeElements(list, n)
print(print_list(flag))
10、删除倒数第n个结点
题目:LeetCode19
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
方法:双指针。定义fast和slow两个指针,fast先走N步,然后slow再开始走,当fast走到队尾的时候,slow就是我们要删除的结点。
Java代码:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = head;
ListNode slow = dummy;
for(int i = 0; i < n; i ++){
fast = fast.next;
}
while(fast != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
Python代码:
def removeNthFromEnd(self, head, n):
dummy = ListNode(0, head)
fast = head
slow = dummy
for i in range (1, n):
fast = fast.next
while(fast.next):
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return dummy.next
C语言代码:
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
dummy->val = 0;
dummy->next = head;
struct ListNode* fast = head;
struct ListNode* slow = dummy;
for(int i = 0; i < n; i ++){
fast = fast->next;
}
while(fast != NULL){
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return dummy->next;
}
11、删除重复元素(重复元素保留一个)
题目:LeetCode83
给定一个已排序的链表的头 head ,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。
示例:
输入:head = [1,1,2]
输出:[1,2]
方法:从指针cur指向链表的头结点,随后开始对链表进行遍历。如果当前cur与cur对应的元素相同,那么我们就将cur.next从链表中移除;否则执行cur = cur.next;当遍历完整个链表之后,返回链表的头结点。
Java代码:
public ListNode deleteDuplicates(ListNode head) {
if(head == null){
return head;
}
ListNode cur = head;
while(cur.next != null){
if(cur.val == cur.next.val){
cur.next = cur.next.next;
}
else{
cur = cur.next;
}
}
return head;
}
Python代码:
def deleteDuplicates(self, head):
if not head:
return head
cur = head
while cur.next:
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head
C语言代码:
struct ListNode* deleteDuplicates(struct ListNode* head) {
if(head == NULL){
return head;
}
//创建结点这么写
//struct ListNode* cur = (struct ListNode* )malloc(sizeof(struct ListNode));
//创建链表这么写
struct ListNode* cur = head;
while(cur->next != NULL){
if(cur->val == cur->next->val){
cur->next = cur->next->next;
}
else{
cur = cur->next;
}
}
return head;
}
Python代码(本地编辑器测试):
class ListNode(object):
def __init__(self, val = None, next = None):
self.val = val
self.next = next
def init_list(nums):
tem_node = ListNode()
tem = ListNode()
for i in nums:
if tem_node.val == None:
tem_node.val = i
tem = tem_node
else:
tem_node.next = ListNode(i)
tem_node = tem_node.next
return tem
class DeleteDuplicates:
def deleteDuplicates(self, head):
if not head:
return head
cur = head
while cur.next:
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head
#打印链表
def print_list(head):
if not head or not head.next:
return []
result = []
while head:
result.append(head.val)
head = head.next
return result
if __name__ == "__main__":
nums = [1, 1, 2, 3, 3]
list = init_list(nums)
deleteDuplicates = DeleteDuplicates()
node = deleteDuplicates.deleteDuplicates(list)
s = print_list(node)
print(s)
12、删除重复元素(重复元素都不要)
题目:LeetCode82
给定一个已排序的链表的头 head ,删除原始链表中所有重复数字的节点,只留下不同的数字。返回已排序的链表。
示例:
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
方法:当一个都不要时,记下结点(cur.next)的val,把cur.next以及cur.next.next两个node与之相比较就行了。这里要注意两个node可能为空,要稍加判断。
Java代码:
public ListNode deleteDuplicates(ListNode head) {
if(head == null){
return head;
}
ListNode dummy = new ListNode(0,head);
ListNode cur = dummy;
//这里这样写是因为下面的if要判断cur.next.next.val
while(cur.next != null && cur.next.next != null){
if(cur.next.val == cur.next.next.val){
int x = cur.next.val;
while(cur.next != null && cur.next.val == x){
cur.next = cur.next.next;
}
}
else{
cur = cur.next;
}
}
return dummy.next;
}
Python代码:
def deleteDuplicates(self, head):
if not head:
return head
dummy = ListNode(0, head)
cur = dummy
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
x = cur.next.val
while cur.next and cur.next.val == x:
cur.next = cur.next.next
else:
cur = cur.next
return dummy.next
C语言代码:
struct ListNode* deleteDuplicates(struct ListNode* head) {
if(head == NULL){
return head;
}
struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
dummy->val = 0;
dummy->next = head;
struct ListNode* cur = dummy;
while(cur->next != NULL && cur->next->next != NULL){
if(cur->next->val == cur->next->next->val){
int x = cur->next->val;
while(cur->next != NULL && cur->next->val == x){
struct ListNode* temp = cur->next;
cur->next = cur->next->next;
free(temp);
}
}
else{
cur = cur->next;
}
}
return dummy->next;
}
本篇文章为原创文,欢迎转载,请注明文章出处https://blog.csdn.net/2301_79084755/article/details/136360792。技术类文章一般都有时效性,本人会不定期对自己的博客进行修正更新,因此请访问出处以查看本文的最新版本。