1、输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
(来自剑指offer 06)
思路:①利用栈 先遍历链表并将每个节点的值压入栈中,然后从栈顶开始依次取出栈中元素作为数组输出。
时间复杂度和空间复杂度均为:O(n)
代码如下:
int* reversePrint(struct ListNode* head, int* returnSize){
int stack[10000]; // 辅助栈
int top = 0; //栈顶指针
struct ListNode *q = head; //头节点
while(q!=NULL){
stack[top++]=q->val;
q=q->next; //将链表中每个节点的值放入栈中
}
*returnSize=top; //size
int* res=(int*)malloc(sizeof(int)*(*returnSize)); //malloc一段空间
for(int i=top-1,j=0;i>=0;i--,j++)
{
res[j]=stack[i]; //从栈顶取出值
}
return res;
}
思路②:先反转链表,获取链表的长度,malloc一个数组,将反转后的链表对应的节点的值保存到数组中。
int length(struct ListNode* head)
{
struct ListNode* p=head;
int len=0;
while(p!=NULL){
len++;
p=p->next;
}
return len;
}
int* reversePrint(struct ListNode* head, int* returnSize){
int len=length(head);
int* res=(int*)malloc(sizeof(int)*len);
struct ListNode* p=head;
*returnSize=len;
for(int i=len;i>0;i--){
res[i-1]=p->val;
p=p->next;
}
return res;
}
2、给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。
返回删除后的链表的头节点。
(剑指offer 18)
思路① 找到待删除的节点val,和前一节点p 将p->next改为p->next->next
(注意头节点)
struct ListNode* deleteNode(struct ListNode* head, int val){
if(head->val==val){
return head->next; //如果是头结点删除 直接head指向next
}
struct ListNode* p=head;
while((p->next!=NULL)&&(p->next->val!=val)){ //判断是否找到待删除的节点
p=p->next;
}
if(p->next!=NULL){ //找到节点
p->next=p->next->next;
}
return head;
}
思路② 双指针(leedcode题解)
1、设置两个指针分别指向头节点,pre (待删除节点的前一节点)和 cur (当前节点);
2、遍历整个链表,查找节点值为 val 的节点,找到了就删除该节点,否则继续查找。
2.1. 找到,将当前节点的前驱节点(pre 节点或者说是之前最近一个值不等于 val 的节点)连接到当前节点(cur 节点)的下一个节点(pre->next = cur->next)。
2.2. 没找到,继续遍历(cur = cur->next),更新最近一个值不等于 val 的节点(pre = cur)。
struct ListNode* deleteNode(struct ListNode* head, int val){
if(head->val == val) { // 头节点为待删除的节点
return head->next;
}
struct ListNode* cur = head; // 当前节点
struct ListNode* pre = head; // 保存待删除节点的前一节点
while (cur != NULL && cur->val != val) {
pre = cur;
cur = cur->next;
}
if (cur != NULL) {
pre->next = cur->next;
}
return head;
}
3、反转链表
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
(剑指offer 24)
思路①迭代
在遍历链表时,将当前的节点的next指针改为指向前的一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。
struct ListNode* reverseList(struct ListNode* head){
if(head == NULL || head->next == NULL)
{
return head;
}
struct ListNode* pre=NULL;
struct ListNode* next=NULL;
while(head!=NULL)
{
next=head->next;
head->next=pre;
pre=head;
head=next;
}
return pre;
}
②头插法
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
newhead->next=NULL; //设置一个新的头节点
struct ListNode* p=(struct ListNode*)malloc(sizeof(struct ListNode));
p=head; //遍历指针
while(p!=NULL){
struct ListNode* n=(struct ListNode*)malloc(sizeof(struct ListNode));
n=p; //新指针
p=p->next; //遍历
n->next=newhead->next; //组成新的链表
newhead->next=n;
}
return newhead->next;
}
4、合并两个排序的链表
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(!l1){
return l2;
}
if(!l2)
{
return l1; //空链表 返回另外一个链表
}
struct ListNode*p =NULL;
if(l1->val < l2->val){
p=l1; //l1大及排到前面
p->next=mergeTwoLists(l1->next,l2);
}else{
p=l2;
p->next=mergeTwoLists(l1,l2->next);
}
return p;
}
5、回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
思路类似回文序列
bool isPalindrome(struct ListNode* head){
int a[1000001];
int i=0,j=0;
struct ListNode*p=head;
while(p!=NULL){
a[i++]=p->val;
p=p->next;
}
while(j<i-1){
if(a[j]!=a[i-1])
return false;
j++,i--;
}
return true;
}