算法训练第三天 | LeetCode 203、707、206
LeetCode 203
题目简述:删除为指定值的节点
思路分析:设置虚拟头结点(dummyhead),从而避开对删除结点的三种讨论:删除头结点,删除中间结点,删除尾结点
我们需要设计一个cur(current)指针指向头结点,并让它一直移动到表尾
设计一个tmp指针,负责结点删除
class Solution {
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){
ListNode*tmp=cur->next;
cur->next=cur->next->next;//向后移动
delete tmp;
}
else{
cur=cur->next;//向后移动
}
}
head=dummyhead->next;//dummyhead->next可能发生了变化
delete dummyhead;
return head;
}
};
非虚拟头节点版本
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
//直接用tmp指针删除head,无需动用cur指针
while(head!=NULL&&head->val==val){
ListNode* tmp=head;
head=head->next;
delete tmp;
}
ListNode*cur=head;
while(cur!=NULL&&cur->next!=NULL){
if(cur->next->val==val){
ListNode*tmp=cur->next;
cur->next=cur->next->next;//向后移动
delete tmp;
}
else{
cur=cur->next;//向后移动
}
}
return head;
}
};
LeetCode 707
题目简析:自行设计出指定要求的链表函数在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
思路分析:设计虚拟头结点,统一链表
class MyLinkedList {
public:
//定义链表结点结构体
sturct LinkedNode{
int val;
LinkedNode* next;
LinkedNode(int val):val(val),next(nullptr)
//构造函数,参数有val,next
};
//初始化链表
MyLinkedList(){
_dummyhead= new LinkedNode(0);//看private,学习这种数据处理方式
_size=0;//私有成员命名方式
}
int get(int index){
if(index>(_size-1)||(index<0)){
return -1'
}
LinkedNode*cur=_dummyhead->next;
while(index--){//循环N次
cur=cur->next;
}
return cur->val
}
void addAtHead(int val){
LinkedNode*newnode=new LinkedNode(val);
newnode->next=_dummyhead->next;
_dummyhead->next=newnode;
}
void addAtTail(int val){
LinkedNode*newnode=new LinkedNode(val);
LinkedNode*cur=_dummyhead;
while(cur!=nullptr){
cur=cur->next;
}
cur->next=newnode;
_size++;
}
void addAtIndex(int index, int val) {
if(index<0)index =0;
if(index>_size)return;
LinkedNode*newnode=new LinkedNode(val);
LinkedNode*cur=_dummyhead;
while(index--){
cur=cur->next;
}
newnode->next=cur->next;
cur->next=newnode;
_size++;
}
void deleteAtIndex(int index) {
if(index>_size||index<0) {return;}
LinkedNode*cur=_dummyhead;
while(index--){
cur=cur->next;
}
LinkednNode*tmp=cur->next;
cur->next=cur->next->next;
delete tmp;
_size--
}
void printLinkedList() {
LinkedNode* cur = _dummyHead;
while (cur->next != nullptr) {
cout << cur->next->val << " ";
cur = cur->next;
}
cout << endl;
}
private:
int _size;
LinkedNode* _dummyHead;
};
技巧总结
while{index--}
等效于for(int i=0;i<=index;i++)
LeetCode 206
题目简析:反转链表
思路分析:设立双指针,一个表示新链表的尾结点,一个表示原链表的头结点。将原链表的结使用头插法到新链表的尾结点就能完成反转的操作。遍历的终止条件是,当遍历完了原链表,所以是cru!=null
public ListNode reverseList(ListNode head) {
//设立双指针,一个指向链表头部,另一个用来作为链表尾部
//使用头插法即可
//链表尾部下一个为空,所以pre从空开始
//头变尾,所以cru从头部开始
ListNode pre = null, cru = head;
while(cru!=null){
//建立一个结点作为临时结点来保存当前结点的下一个
ListNode node = cru.next;
//搞清楚链接关系----原链表的当前结点经过头插法后链接到新链表的尾部
cru.next = pre;
//更新尾结点,将新的pre作为尾结点
pre = cru;
//更新待头插入的结点---即原来cru的.next
cru = node;
}
//头插法后pre是新链表的头结点
return pre;
}