学习目录
1.学习目标
1.按照如下类型来刷题:数组-> 链表-> 哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目。
2.动手用多种语言来进行写题,并要有自己的代码模板。
3.总结程序员简历技巧。
2.链表
2.1 题目
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
2.2 思考
题目绝对是好题,把链表的各种操作都考察了,没有涉及任何算法,但是对链表的理解是大有帮助。这在大一的时候应该是作为一个课后作业实现的,然后今天稍微写了下,还算是写的合格吧!!!
然后写的过程自己也总结了自己写链表的几个要点,大佬们莫笑!!!!
(1)链表结构(偷懒法)
我之前链表结构的声明十分的随便(其实已经忘的差不多了),但是在做链表结构的时候,如果对结构真的理解不怎么透彻,可以偷下懒:
typedef struct MyLinkedList{
int val;
struct MyLinkedList *next;
} MyLinkedList;
就是把结构体类型名和变量名用一个表示,这样就可以避免少量的错误,但如果想真的理解结构还是得认真学习和总结。
(2)虚拟头节点
这个在上篇也讲过,在链表中使用一个虚拟头节点对于删除头节点以及存储相关数据是真的有帮助,大家可以用一下。
(3)插入节点
我之前有个错误就是插入节点,当时我就是按照习惯写了判断,如果索引大于链表长度则直接返回,结果少考虑插入到最后一个节点的可能,算是判断失误。
(4)代码
渣渣的代码:
typedef struct MyLinkedList{
int val;
struct MyLinkedList *next;
} MyLinkedList;
/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
MyLinkedList *p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p->val=-1;
p->next=NULL;
return p;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
if(obj->val<index) return -1;
MyLinkedList *p;
p=obj;
for(int i=0;i<=index;i++) p=p->next;
return p->val;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
MyLinkedList *p=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p->val=val;
p->next=obj->next;
obj->next=p;
obj->val++;
}
/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
MyLinkedList *p,*q=(MyLinkedList*)malloc(sizeof(MyLinkedList));
p=obj;
for(int i=0;i<=obj->val;i++)
{
p=p->next;
}
p->next=q;
q->next=NULL;
q->val=val;
obj->val++;
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if(obj->val<index-1)
return ;
MyLinkedList *p;
p=obj;
for(int i=0;i<index;i++) p=p->next;
MyLinkedList *q=(MyLinkedList*)malloc(sizeof(MyLinkedList));
q->val=val;
q->next=p->next;
p->next=q;
obj->val++;
}
/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if(obj->val<index)
return ;
MyLinkedList *p,*q;
p=obj;
for(int i=0;i<index;i++) p=p->next;
q=p->next;
p->next=p->next->next;
free(q);
obj->val--;
}
void myLinkedListFree(MyLinkedList* obj) {
}
/**
* Your MyLinkedList struct will be instantiated and called as such:
* MyLinkedList* obj = myLinkedListCreate();
* int param_1 = myLinkedListGet(obj, index);
* myLinkedListAddAtHead(obj, val);
* myLinkedListAddAtTail(obj, val);
* myLinkedListAddAtIndex(obj, index, val);
* myLinkedListDeleteAtIndex(obj, index);
* myLinkedListFree(obj);
*/
3.链表
3.1题目
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
3.2思考
这个思路也有很多,最差都能想到的是再申请一个空间,然后遍历一遍就行,但是这个方法十分耗费空间。这里我使用了几个指针进行操作就能实现反转,代码也十分的简单,大概就是一个指针pre,一个指针p,一个指针temp。首先,pre表示p前的节点,最开始的时候可以初始化为NULL,然后temp存储原p->next,因为p反转之后就找不到next了。
算法开始:
temp=p->next;//temp存储p下一个节点,避免找不到
p->next=pre;//反转
pre=p;//恢复
p=temp;
3.3 代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode *pre,*temp,*p;
pre=NULL;
temp=NULL;
p=head;
while(p!=NULL)
{
temp=p->next;
p->next=pre;
pre=p;
p=temp;
}
return pre;
}
4.链表(环)
4.1题目
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
4.2 思考
常见面试题,我第一次面试被问到时啥都不知道,这道题就快慢指针可以实现。需要一定程度的数学运算能力,初次遇见可能就是像我一样全部遍历得结果,蠢的不行,还一个劲的和面试官说,这算法就是O(n^2),没有更优的,回想起当时,真的慢慢的耻辱感。
这道题主要考察两个知识点,环链1考察的是判断有没有环,环2考察的是有没有环,且判断路口,因涉及到一定的运算,我就简述下算法。具体证明看这里。
(1)判断有无环
这个很简单,设置快慢指针,一个步伐为2,一个步伐为1,然后开始遍历,如果二者相遇表示存在环,否则就是没有。
(2)环的入口
环的入口的算法是有一点数学证明的,还是双指针法,一个从起点出发,一个从前面的相遇点出,他们相遇的位置就是入口。
5.闲聊
最近事情也多,最近有几场面试还有毕设的开题报告,只能是每天抽时间来写了,因为今天想快点把链表结束,所以就仓促的全部写完。嗯嗯嗯,马上要出成绩了,听说今年初试预测线350,看来没太大希望了。