链表回文
第一题
bool isPalindrome(struct ListNode* head){
struct ListNode*cur=head;
struct ListNode*vec[100001];
int i=0;
while(cur)
{
vec[i]=cur->val;
cur=cur->next;
i++;
}
int p=0;
int q=i-1;
while(p<q)
{
if(vec[p]!=vec[q])
{
return false;
}
else{
p++;
q--;
}
}
return true;
}
思路:将所有链表数据存入数组,用双指针比较
链表逆序
第一题
int* reversePrint(struct ListNode* head, int* returnSize){
static int ret[10000];
struct ListNode*cur=head;
int i=0;
while(cur)
{
ret[i++]=cur->val;
cur=cur->next;
}
int q=i-1;
for(int j=0;j<i/2;j++)
{
int temp=ret[j];
ret[j]=ret[q];
ret[q]=temp;
q--;
}
*returnSize=i;
return ret;
}
第二题
struct ListNode* reverseList(struct ListNode* head){
struct ListNode*cur=head;
int num=0;
struct ListNode*vec[5001];
if(head==NULL)
{
return NULL;
}
while(cur)
{
vec[num++]=cur;
cur=cur->next;
}
int temp=num-1;
for(int j=num-1;j>0;j--)
{
vec[j]->next=vec[j-1];
}
vec[0]->next=NULL;
return vec[temp];
}
第三题 反转链表2
void reverse(struct ListNode*head)
{
struct ListNode*pre=NULL;
struct ListNode*cur=head;
while(cur!=NULL)
{
struct ListNode*next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
}
struct ListNode* reverseBetween(struct ListNode* head, int left, int right){
struct ListNode*dummyhead=malloc(sizeof(struct ListNode));
dummyhead->val=0;
dummyhead->next=head;//虚拟头结点写法,用于头结点可能改变时
struct ListNode*pre=dummyhead;
for(int i=0;i<left-1;i++)//虚拟头结点走left-1步来到left前一个结点
{
pre=pre->next;
}
struct ListNode*rightt=pre;
for(int i=0;i<right-left+1;i++)//来到right结点
{
rightt=rightt->next;
}
struct ListNode*leftnode=pre->next;
struct ListNode*rightnode=rightt->next;//right的后面
pre->next=NULL;
rightt->next=NULL;
reverse(leftnode);
pre->next=rightt;
leftnode->next=rightnode;
return dummyhead->next;
}
注意:
(1)虚拟头结点的写法,dummyhead->next=head
(2)翻转链表函数的简易写法
void reverse (struct Listnode* head)
{
struct Listnode*pre=NULL;
struct Listnode* cur=head;
while(cur)
{
struct Listnode* next=cur->next;//记录cur->next
cur->next=pre;
pre=cur;
cur=next;
}
(3)如何获得链表中特定结点
for循环,记录步数
(4)用reverse函数后,之前记录的结点仍不变,只是后继结点改变而已,因此reverse后直接接上即可
第四题
两数相加2
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode*cur=l1;
struct ListNode*vec1[101];
struct ListNode*ret[101];
int len1=0;
int m1=0;
while(cur)
{
vec1[m1++]=cur;
len1++;
cur=cur->next;
}
struct ListNode*cur2=l2;
struct ListNode*vec2[101];
int len2=0;
int m2=0;
while(cur2)
{
vec2[m2++]=cur2;
len2++;
cur2=cur2->next;
}
if(len1>=len2)
{
int temp=len1-len2;
int q1=len1-1;
int q2=len2-1;
int add=0;
for(int i=q1;i>=temp;i--)
{
int temp2=vec1[i]->val+vec2[q2--]->val+add;
if(temp2>=10)
{
add=1;
temp2=temp2-10;
}
else{
add=0;
}
vec1[i]->val=temp2;
}
return vec1[0];
}
else{
int temp=len2-len1;
int q1=len1-1;
int q2=len2-1;
int add=0;
for(int i=q2;i>=temp;i--)
{
int temp3=vec2[q2]->val+vec1[q1--]->val+add;
if(temp3>=10)
{
add=1;
temp3=temp3-10;
}
else{
add=0;
}
vec2[i]->val=temp3;
}
return vec2[0];
}
return 0;
}
实在看不懂题解里的栈,我是废物
下为翻转函数头尾指针版,返回的是翻转后的头
struct ListNode*reverse(struct ListNode*head,struct ListNode*tail){
if(head->next==tail)
return head;
struct ListNode*p1=reverse(head->next,tail);
head->next->next=head;
head->next=NULL;
return p1;
}
链表遍历
第一题
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* small=malloc(sizeof(struct ListNode));
struct ListNode*p1=small;
struct ListNode*smallhead=small;
struct ListNode* big=malloc(sizeof(struct ListNode));
struct ListNode*p2=big;//因为是新链表所以要malloc
struct ListNode*largehead=big;
struct ListNode*cur=head;
while(cur)
{
if(cur->val<x)
{
p1->next=cur;
cur=cur->next;
p1=p1->next;
}
else
{
p2->next=cur;
cur=cur->next;
p2=p2->next;
}
}
p2->next=NULL;
p1->next=largehead->next;
return smallhead->next;
}
维护两个链表,一个小于x,一个大于等于x
第二题
struct ListNode* swapNodes(struct ListNode* head, int k){
struct ListNode *tar1,*tar2;//目标结点
int num=0;
struct ListNode *fast;
fast=head;
tar2=head;
while(--k)
{
fast=fast->next;
}
tar1=fast;//此时tar1为第k个结点
while(fast->next)
{
fast=fast->next;
tar2=tar2->next;//此时tar2为倒数第k个结点
}
num=tar1->val;
tar1->val = tar2->val;
tar2->val = num;
return head;
}
一次遍历找到第k个和倒数第k个,先遍历k-1次,找到第k个,然后让fast继续遍历len-(k-1)次,tar2同时从头开始遍历len-(k-1)次
链表结点删除
第一题
struct ListNode* deleteNode(struct ListNode* head, int val){
struct ListNode*dummyhead=malloc(sizeof(struct ListNode));
dummyhead->next=head;
dummyhead->val=-1;//虚拟头指针
struct ListNode*cur=head;
if (cur->val == val) {
return cur->next;
}
while(cur)
{
if(cur->next->val==val)
{
cur->next=cur->next->next;
break;
}
cur=cur->next;
}
return dummyhead->next;
}
第二题
void deleteNode(struct ListNode* node) {
node->val=node->next->val;
node->next=node->next->next;
}
将next赋值给node,把next的next赋值给node的next
第三题
struct ListNode* removeZeroSumSublists(struct ListNode* head){
struct ListNode*pre=malloc(sizeof(struct ListNode));
pre->next=head;
pre->val=0;
struct ListNode*left=pre;
int sum;
while(left)
{
sum=0;
struct ListNode*right=left->next;
while(right)
{
sum+=right->val;
if(sum==0)
{
left->next=right->next;
}
right=right->next;
}
left=left->next;
}
return pre->next;
}
思路:维护n方的前缀和,注意第一次的left从头结点的前继结点开始算,因为right=left->next,让right从头结点开始算
链表索引
第一题
struct ListNode* middleNode(struct ListNode* head){
struct ListNode*fast=head;
struct ListNode*slow=head;
while(fast!=NULL&&fast->next!=NULL)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
找中间结点,快指针一次走两步,慢指针一次走一步,当快指针走到表尾或快要走到表尾时,慢指针就会达到中间结点
第二题
int* nextLargerNodes(struct ListNode* head, int* returnSize){
struct ListNode*left=head;
int *ret = (int*)malloc(sizeof(int)*10001);
memset(ret,0,sizeof(int)*10001);
int i=0;
while(left)
{
struct ListNode*right=left->next;
while(right)
{
if(right->val>left->val)
{
ret[i]=right->val;
break;
}
right=right->next;
ret[i]=0;
}
i++;
left=left->next;
}
*returnSize=i;
return ret;
}
链表交换
第一题
struct ListNode* swapPairs(struct ListNode* head) {
struct ListNode dummyHead;
dummyHead.next = head;
struct ListNode* temp = &dummyHead;
while (temp->next != NULL && temp->next->next != NULL) {
struct ListNode* node1 = temp->next;
struct ListNode* node2 = temp->next->next;
temp->next = node2;
node1->next = node2->next;
node2->next = node1;
temp = node1;
}
return dummyHead.next;
}
思路:当需要分组作业时,可以不用划分特定组,可以像这道题一样,规定一个temp做检测变量,每次变换temp后的两个结点,最后把第二个结点赋值给temp即可