问题1
设计算法,将带头结点的单链表原地反转,原地是指辅助空间复杂度为O(1)。
题解1
时间复杂度: O(n) 空间复杂度 O(1)
因为链表,如果你把第i+1个节点的 next值,设置为第i个节点,那么你就丢掉了第i+2个节点,因此我需要三个变量,时刻保存这三个节点。
c++:
#include <iostream>
using namespace std;
struct Node {
int val;
Node * next = nullptr;
};
Node * reverse(Node * head){
Node * next = head->next;
head->next = nullptr;
while(next != nullptr){
Node * next_next = next->next;
next->next = head;
head = next;
next = next_next;
}
return head;
}
void print_List(Node * head){
while (head != nullptr){
cout << head->val << " ";
head = head->next;
}
cout << endl;
}
int main() {
//首先生成一个列表
Node nodes [10];
for(int i = 0;i < 10 ; i ++){
nodes[i] = Node{i};
}
for(int i = 1;i < 10;i ++){
nodes[i - 1].next = & nodes[i];
}
//打印列表
print_List(& nodes[0]);
//反转
auto new_head = reverse(&nodes[0]);
//再次打印
print_List(new_head);
}
python:
class Node:
def __init__(self,val : int, next = None):
self.val = val
self.next = next
def Reverse(head : Node) -> Node:
'''
输入头结点,逆转列表,返回尾结点,也就是新的头结点
:param head:
:return:
'''
next= head.next #记录下当前操作的节点的下一个节点
head.next = None #因为头结点是翻转后的尾结点,因此尾结点next是None 因此把head.next 设置为None
while next != None:
next_next = next.next #记录下一个节点的下一个节点
next.next = head #让下一个节点指向当前操作的
head = next #让当前操作的节点变成下一个
next = next_next # 更新next的值
return head
def Print_Listnodes(head : Node):
'''
打印链表
:param head:
:return:
'''
while head != None:
print(head.val,end=" ")
head = head.next
print()
if __name__ == "__main__":
#新建一个链表
head = Node(0)
p = head
for i in range(1,10):
new_node = Node(i)
p.next = new_node
p = new_node
#打印链表
Print_Listnodes(head)
#反转链表并获得新头
new_head = Reverse(head)
#打印反转后的
Print_Listnodes(new_head)
问题2
设计一个算法,判断一个链表是否有环,如果有,找出环的入口点并返回,否则返回NULL。链表结构可如下考虑:
题解2
时间复杂度O(n) 空间复杂度O(1)
#include <iostream>
using namespace std;
struct Node {
int val;
Node * next = nullptr;
};
Node * FindLoopStart(Node * head){
Node * slow = head, *fast = head;
while (fast != nullptr){
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
break;
}
if(fast == nullptr)
return nullptr;
Node * root = head;
while (root != slow){
root = root->next;
slow = slow->next;
}
return root;
}
void print_List(Node * head){
while (head != nullptr){
cout << head->val << " ";
head = head->next;
}
cout << endl;
}
int main() {
Node nodes [10];
//构建一个带环的列表 大概就是 0->1->2->3->....->9 ->0
for(int i = 0;i < 10 ; i ++){
nodes[i] = Node{i};
}
for(int i = 1;i < 10;i ++){
nodes[i - 1].next = & nodes[i];
}
//nodes[9].next = &nodes[5];
//找到环的入口
auto new_head = FindLoopStart(&nodes[0]);
//输出环入口值
if (new_head != nullptr)
cout << new_head->val;
else
cout << "No loop in the list";
}
问题3
题目来源:https://leetcode-cn.com/problems/remove-duplicate-node-lcci/
编写代码,移除未排序链表中的重复节点。保留最开始出现的节点
题解3
时间复杂度O(n),空间复杂度O(1)
即开设一个很大的数组,用来保存元素值是否访问过
c++ :
class Solution {
public:
ListNode* removeDuplicateNodes(ListNode* head) {
if( head == nullptr) return head;
bool valexist[20001] = {};
ListNode * previous_node = head;
ListNode * in_hand_node = head->next;
valexist[head->val] = true;
while (in_hand_node != nullptr){
if(valexist[in_hand_node->val]){
//表明出现过这个值,移除这个节点
previous_node->next = in_hand_node->next;
}
else{
//没有出现过这个值,记录这个节点
valexist[in_hand_node->val] = true;
previous_node = in_hand_node;
}
in_hand_node = in_hand_node->next;
}
return head;
}
};
python:
class Solution:
def removeDuplicateNodes(self, head: ListNode) -> ListNode:
valexisted = [False] * 20001
if head == None: return None
previous_node = head
assert id(previous_node) != id(head)
valexisted[previous_node.val] = True
in_hand_node = head.next
while in_hand_node != None:
if valexisted[in_hand_node.val]:
previous_node.next = in_hand_node.next
else:
valexisted[in_hand_node.val] = True
previous_node = in_hand_node
in_hand_node = in_hand_node.next
return head