这道题可以直接求出链表的长度,然后求出它用len - n 不就是正数的长度吗?就会把问题编程了删除正数第几个节点,那种方式就不写了,看下面的其他两种吧。
#define MAX_SIZE 31
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode** stack = (struct ListNode**)malloc(sizeof(struct ListNode*) * MAX_SIZE);
int top = 0;
struct ListNode* cur = head;
while(cur != NULL)
{
//入栈
stack[++top] = cur;
cur = cur -> next;
}
int index = top - n + 1;
if(index == 1)
{
//头删
head = head -> next;
return head;
}
struct ListNode* prev = stack[index - 1];
prev -> next = stack[index] -> next;
free(stack[index]);
return head;
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode* fast = head;
struct ListNode* slow = head;
//fast 比 slow 快 n 个
while(n != 0)
{
fast = fast -> next;
n--;
}
//当fast 走完时候,slow 就是需要删除的节点
struct ListNode* prev = NULL;
while(fast != NULL)
{
prev = slow;
slow = slow -> next;
fast = fast -> next;
}
if(prev == NULL)
{
//头删
head = head -> next;
return head;
}
prev -> next = slow -> next;
free(slow);
return head;
}
struct ListNode* FindEndth(struct ListNode* head, int k,struct ListNode** prev)
{
struct ListNode* fast = head;
struct ListNode* slow = head;
while(k != 0)
{
*prev = fast;
fast = fast -> next;
k--;
}
while(fast != NULL)
{
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
struct ListNode* swapNodes(struct ListNode* head, int k)
{
struct ListNode* begin = head;
struct ListNode* end = FindEndth(head,k,&begin);
//交换
int tmp = begin -> val;
begin -> val = end -> val;
end -> val = tmp;
return head;
}
题目中给你两个数,这俩数本来就是逆序的给你的,然后将这俩数加起来的和存储到链表中去。
我没看到题目里加粗的那俩大字逆序,完了我手动逆序了一下。。。
关键是啥,前三个测试用例你看。
第一个是不管逆序不逆序,结果竟然都一样,而后俩,数都一样,逆序了肯定也一样。
所以前三个就这样过了,结果一提交,错了。
struct ListNode* BuyNode(int* sum)
{
struct ListNode* nweNode = (struct ListNode*)malloc(sizeof(struct ListNode));
nweNode -> val = (*sum % 10);
*sum /= 10;
return nweNode;
}
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2)
{
struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur = head;
struct ListNode* cur1 = l1;
struct ListNode* cur2 = l2;
int sum = 0;
while(cur1 != NULL || cur2 != NULL || sum != 0)
{
if(cur1 != NULL)
{
sum += cur1 -> val;
cur1 = cur1 -> next;
}
if(cur2 != NULL)
{
sum += cur2 -> val;
cur2 = cur2 -> next;
}
//指向下一个节点
cur -> next = BuyNode(&sum);
cur = cur -> next;
}
cur -> next = NULL;
return head -> next;
}
这道题是给你两个链表,然后再给你两个下标[a,b],注意是下标,将list1中[a,b]区间的值换成list2
就好了。
struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2)
{
struct ListNode* prev = NULL,*begin = list1, *end = list1 -> next;
int i = 0, j = 1;
//确定删除区间
while(i != a || j != b)
{
if(i != a)
{
i++;
prev = begin;
begin = begin -> next;
}
if(j != b)
{
j++;
end = end -> next;
}
}
//找到list2的尾
struct ListNode* tail = list2;
while(tail -> next != NULL)
{
tail = tail -> next;
}
prev -> next = list2;
tail -> next = end -> next;
return list1;
}
题目要求给我们一个链表,然后再给一个k,k决定你旋转几次链表。
看上图可以发现,就是说如果k % 链表长度为0的话,那么就是原地,不进行旋转。
相应的,roate k,就是从倒数第k的位置进行截断,将其变成新的头节点。
没错,我又用到了倒数第k个节点这个函数
有了以上规律我们就好做了。
首先遍历一遍原来的链表,对其进行求长度的同时,得到链表最后一个节点。
然后判断k%len 决定k是进行旋转多少次,取倒数第几个。
prev -> next = NULL, tail -> next = head;
return cur;
//找出倒数第n个节点,并且还得拿prev记录前一个
struct ListNode* FindNthEnd(struct ListNode* head,struct ListNode** prev, int n)
{
struct ListNode* slow = head, *fast = head;
while(n != 0)
{
fast = fast -> next;
n--;
}
while(fast != NULL)
{
*prev = slow;
slow = slow -> next;
fast = fast -> next;
}
return slow;
}
struct ListNode* rotateRight(struct ListNode* head, int k)
{
if(head == NULL)
{
return head;
}
int len = 1;
struct ListNode* tail = head;
//找尾,同时记录出长度
while(tail -> next != NULL)
{
len++;
tail = tail -> next;
}
k %= len;
if(k == 0)
{
return head;
}
struct ListNode* prev = NULL;
struct ListNode* cur = FindNthEnd(head,&prev,k);
prev -> next = NULL;
tail -> next = head;
return cur;
}
这道题的是要将下标为奇数的全部放在左边,下标为偶数的全部放在右边,第一个按所以1为计算。
struct ListNode* oddEvenList(struct ListNode* head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct ListNode* oddHead = head, *evenHead = head -> next;
struct ListNode* oddTail = head, *evenTail = head -> next;
while(evenTail != NULL && evenTail -> next != NULL)
{
oddTail -> next = oddTail -> next -> next;
oddTail = oddTail -> next;
evenTail -> next = evenTail -> next -> next;
evenTail = evenTail -> next;
}
oddTail -> next = evenHead;
return oddHead;
}
我们只有先改变cur -> next = next -> next. 如果先改变了next -> next = cur,那么节点3就找不到了
最后一步,便是next -> next = cur。
此时 2 和 1已经交换完成,而下一次需要交换的是 3 和 4
所以此时,拿1 充当对于 3 和 4的头节点 ,也是 prev.
这样子就会使其一直走下去,除非遇到下面这种情况是无法再继续了。
struct ListNode* swapPairs(struct ListNode* head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead -> next = head;
struct ListNode* prev = newHead;
struct ListNode* cur = NULL;
struct ListNode* next = NULL;
while(prev -> next != NULL && prev -> next -> next != NULL)
{
cur = prev -> next;
next = cur -> next;
prev -> next = next;
cur -> next = next -> next;
next -> next = cur;
prev = cur;
}
return newHead -> next;
}
这道题使要求我们,每k个节点然后对其进行翻转链表。
首先我们得学会如何翻转链表,在以前的简单题目中是有刷过的,这里就不重复在写一遍翻转链表的思想。
代码如下:
//逆序链表
struct ListNode* ReverseList(struct ListNode* head)
{
if(head == NULL)
{
return NULL;
}
struct ListNode* newhead = NULL;
struct ListNode* cur = head;
struct ListNode* next = head -> next;
while(cur != NULL)
{
cur -> next = newhead;
newhead = cur;
cur = next;
if(next != NULL)
next = next -> next;
}
return newhead;
}
struct ListNode* reverseKGroup(struct ListNode* head, int k)
{
int len = 0;
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead->next = head;
struct ListNode* begin = head;
//计算出链表的长度
while (begin != NULL)
{
len++;
begin = begin->next;
}
int i = 0;
struct ListNode* prev = newHead;
while (len - i >= k)
{
begin = prev->next;
struct ListNode* end = begin;
//找到当前k的结尾
int j = 1;
while (j != k)
{
j++;
end = end->next;
}
//将end->next = NULL,拿临时指针存储end之后的链表
struct ListNode* tmp = end->next;
end->next = NULL;
//逆序单个子链表
end = ReverseList(begin);
//end将变成开始
prev->next = end;
//而begin将变成结束,连上刚才所断开的tmp
begin->next = tmp;
prev = begin;
i += k;
}
return newHead -> next;
}
题目要求我们将链表进行分割,把所有小于x的放在链表左侧,大于或者等于x的放到链表右侧,从测试用例可以看出,不需要有序也行。
struct ListNode* partition(struct ListNode* head, int x)
{
struct ListNode* bigList = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* bigTail = bigList;
struct ListNode* samllList = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* smallTail = samllList;
struct ListNode* cur = head;
while(cur != NULL)
{
if(cur -> val < x)
{
smallTail -> next = cur;
smallTail = smallTail -> next;
}
else
{
bigTail -> next = cur;
bigTail = bigTail -> next;
}
cur = cur -> next;
}
bigTail -> next = NULL;
smallTail -> next = bigList -> next;
return samllList -> next;
}
这道题是给一个链表,然后将链表分成k份,各个链表长度不能相差不能超过1,然后前面的链表长度得比后面的大。
int GetListLen(struct ListNode* head)
{
struct ListNode* cur = head;
int len = 0;
while(cur != NULL)
{
cur = cur -> next;
len++;
}
return len;
}
struct ListNode** splitListToParts(struct ListNode* head, int k, int* returnSize)
{
struct ListNode** ans = (struct ListNode**)malloc(sizeof(struct ListNode*) * k);
*returnSize = k;
struct ListNode* cur = head;
int len = GetListLen(head);
if(len <= k)
{
//len <= k, 直接按照一个一个分,不够的补NULL
int i;
for (i = 0; i < k; i++)
{
if(cur != NULL)
{
ans[i] = cur;
cur = cur -> next;
ans[i] -> next = NULL;
}
else
{
ans[i] = NULL;
}
}
}
else
{
//len % k 得到的是前几个多放一个。
//len / k 决定每一段放几个。
int tmp = len % k, num = len / k;
int i;
struct ListNode* begin = cur;
//将前几个里面多放一个
for (i = 0; i < tmp; i++)
{
int j = 1;
struct ListNode* end = begin;
while(j != num + 1)
{
end = end -> next;
j++;
}
ans[i] = begin;
begin = end -> next;
end -> next = NULL;
}
//后面的按照num放就好了
for (i; i < k; i++)
{
int j = 1;
struct ListNode* end = begin;
while(j != num)
{
end = end -> next;
j++;
}
ans[i] = begin;
begin = end -> next;
end -> next = NULL;
}
}
return ans;
}
- 0 , n , 1 , n-1, 2 , n - 2 ……………… mid。
//返回链表的中间节点,然后记录前一个出现的节点
struct ListNode* GetListMidNode(struct ListNode* head, struct ListNode** prev)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while(fast != NULL && fast -> next != NULL)
{
*prev = slow;
slow = slow -> next;
fast = fast -> next -> next;
}
return slow;
}
//逆序链表
struct ListNode* ReverseList(struct ListNode* head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct ListNode* newhead = NULL;
struct ListNode* next = head -> next;
while(head != NULL)
{
head -> next = newhead;
newhead = head;
head = next;
if(next != NULL)
{
next = next -> next;
}
}
return newhead;
}
void reorderList(struct ListNode* head)
{
if(head == NULL || head -> next == NULL || head -> next -> next == NULL)
{
return;
}
//获取中间节点
struct ListNode* prev = NULL;
struct ListNode* mid = GetListMidNode(head,&prev);
prev -> next = NULL;
//先将逆序之前的头存储下来
struct ListNode* rearTail = mid -> next;
struct ListNode* rear = ReverseList(mid -> next);
mid -> next = NULL;
rearTail -> next = mid;
//至此前半段和后半段链表依然构成。
struct ListNode* cur1 = head;
struct ListNode* cur2 = rear;
struct ListNode* next1 = head -> next;
struct ListNode* next2 = rear -> next;
while(cur1 != NULL && cur2 != NULL)
{
cur1 -> next = cur2;
if(next1 != NULL)
{
cur2 -> next = next1;
}
cur1 = next1;
cur2 = next2;
if(next1 != NULL)
{
next1 = next1 -> next;
}
if(next2 != NULL)
{
next2 = next2 -> next;
}
}
}
这道题设计一个链表,在数据结构中咱们都学过,我这里直接设计一个双向循环链表。
淦淦!!!
typedef struct Node
{
int val;
struct Node* prev;
struct Node* next;
} MyLinkedList,ListNode;
MyLinkedList* BuyNode(int val)
{
MyLinkedList* newNode = (MyLinkedList*)malloc(sizeof(ListNode));
newNode -> prev = NULL;
newNode -> next = NULL;
newNode -> val = val;
return newNode;
}
MyLinkedList* myLinkedListCreate()
{
//头节点,无意义。
MyLinkedList* obj = BuyNode(-1);
obj -> next = obj;
obj -> prev = obj;
return obj;
}
int myLinkedListGet(MyLinkedList* obj, int index)
{
int i = 0;
ListNode* cur = obj -> next;
while(i != index)
{
cur = cur -> next;
if(cur == obj)
{
return -1;
}
i++;
}
return cur -> val;
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val)
{
ListNode* newNode = BuyNode(val);
if (obj->next != obj)
{
obj->next->prev = newNode;
}
newNode -> next = obj -> next;
newNode -> prev = obj;
obj -> next = newNode;
if(obj -> prev == obj)
{
//没有尾,第一个也是尾
obj -> prev = obj -> next;
}
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val)
{
if (obj->prev == obj)
{
//无节点时候,尾插相等于头插
myLinkedListAddAtHead(obj, val);
}
else
{
ListNode* newNode = BuyNode(val);
ListNode* tail = obj->prev;
newNode->prev = tail;
tail->next = newNode;
newNode->next = obj;
obj->prev = newNode;
}
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val)
{
int i = 0;
ListNode* cur = obj -> next;
while(i != index)
{
if(cur == obj)
{
return;
}
cur = cur->next;
i++;
if (cur == obj && i == index)
{
//等于链表长度进行尾插
myLinkedListAddAtTail(obj, val);
return;
}
}
ListNode* newNode = BuyNode(val);
newNode -> prev = cur -> prev;
newNode -> next = cur;
cur -> prev -> next = newNode;
cur -> prev = newNode;
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index)
{
int i = 0;
ListNode* cur = obj -> next;
while(i != index)
{
cur = cur -> next;
if(cur == obj)
{
//索引大于链表长度,啥也不干
return;
}
i++;
}
cur -> prev -> next = cur -> next;
cur -> next -> prev = cur -> prev;
free(cur);
}
void myLinkedListFree(MyLinkedList* obj)
{
ListNode* cur = obj -> next;
ListNode* prev = cur;
while(cur != obj)
{
prev = cur;
cur = cur -> next;
free(prev);
}
obj -> prev = obj;
obj -> next = obj;
}
这道题目的意思是要我们对链表进行一个插入排序。
当你也可以,转数组,qsort,转链表。三步大功告成,那这样子确实很无趣。
如果对前面的排序不是很了解,在我前面的文章中也有排序。
做链表这种题目,做的多了就会发现用一个头节点来协助我们会方便许多,还是新建一个头节点
拿 prev 和 cur去比较,发现不是大小顺序不对,然后对其进行操作,先将tmp成为head.
然后就行对其进行一个链表的插入了,也可以说是交换吧。
注意步骤的顺序不能变。
struct ListNode* insertionSortList(struct ListNode* head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead -> next = head;
struct ListNode* cur = head -> next, *prev = head, *tmp = NULL;
while(cur != NULL)
{
if(cur -> val >= prev -> val)
{
//去找当前节点比前一个小的节点。
cur = cur -> next;
prev = prev -> next;
}
else
{
//比前面小的节点。
tmp = newHead;
//找合适的位置
while(tmp -> next -> val < cur -> val)
{
tmp = tmp -> next;
}
prev -> next = cur -> next;
cur -> next = tmp -> next;
tmp -> next = cur;
//cur 继续迭代下去
cur = prev -> next;
}
}
return newHead -> next;
}
这道题,说实话,有点意思,哈哈哈。
look picture。
void deleteNode(struct ListNode* node)
{
struct ListNode* prev = node;
struct ListNode* cur = prev -> next;
struct ListNode* next = cur -> next;
prev -> val = cur -> val;
prev -> next = next;
free(cur);
}
这道题是设计一个跳表,在前一篇章节中有讲述C语言实现跳表(附源码)
#define MAX_LEVEL 5
typedef struct SkipNode
{
int val;
int maxLeve;
struct SkipNode** next;
}SkipNode;
typedef struct
{
int level;
SkipNode* head;
} Skiplist;
SkipNode* BuyNode(int level, int val)
{
SkipNode* newNode = (SkipNode*)malloc(sizeof(SkipNode));
newNode -> val = val;
newNode -> maxLeve = level;
newNode->next = (SkipNode**)malloc(sizeof(SkipNode*) * level);
int i;
for (i = 0; i < level; i++)
{
newNode -> next[i] = NULL;
}
return newNode;
}
int GetRandomLevel()
{
int level = 1;
while(rand() % 2)
{
level++;
}
//最大不能超过MAX_LEVEL
return level > MAX_LEVEL ? MAX_LEVEL : level;
}
Skiplist* skiplistCreate()
{
Skiplist* obj = (Skiplist*)malloc(sizeof(Skiplist));
obj -> head = BuyNode(MAX_LEVEL,-1);
obj -> level = 0;
int i;
SkipNode* newHead = BuyNode(MAX_LEVEL,-1);
for (i = 0; i < MAX_LEVEL; i++)
{
obj -> head -> next[i] = newHead;
}
return obj;
}
bool skiplistSearch(Skiplist* obj, int target)
{
if(obj == NULL)
{
return false;
}
SkipNode* cur = NULL;
if(obj -> level > 0)
{
cur = obj -> head -> next[obj -> level - 1];
}
int i;
for (i = obj -> level - 1; i >= 0; i--)
{
while(cur -> next[i] != NULL && cur -> next[i] -> val < target)
{
cur = cur -> next[i];
}
//跳过该层
if(cur -> next[i] == NULL)
{
continue;
}
//找到了
if(cur -> next[i] -> val == target)
{
return true;
}
}
return false;
}
void skiplistAdd(Skiplist* obj, int num)
{
SkipNode** prevNodes = (SkipNode**)malloc(sizeof(SkipNode*) * MAX_LEVEL);
SkipNode* cur = NULL;
if(obj -> level > 0)
{
cur = obj -> head -> next[obj -> level - 1];
}
int i;
for (i = obj -> level - 1; i >= 0; i--)
{
while(cur -> next[i] != NULL && cur -> next[i] -> val < num)
{
cur = cur -> next[i];
}
prevNodes[i] = cur;
}
int suitLevel = GetRandomLevel();
if(suitLevel > obj -> level)
{
for (i = obj -> level; i < suitLevel; i++)
{
prevNodes[i] = obj -> head -> next[i];
}
//更新层数
obj -> level = suitLevel;
}
SkipNode* newNode = BuyNode(suitLevel,num);
//新节点与前面的节点进行链接
for (i = 0; i < suitLevel; i++)
{
newNode -> next[i] = prevNodes[i] -> next[i];
prevNodes[i] -> next[i] = newNode;
}
}
bool skiplistErase(Skiplist* obj, int num)
{
if(!skiplistSearch(obj,num))
{
//没有目标节点
return false;
}
SkipNode** prevNodes = (SkipNode**)malloc(sizeof(SkipNode*) * MAX_LEVEL);
SkipNode* cur = NULL;
if(obj -> level > 0)
{
cur = obj -> head -> next[obj -> level - 1];
}
int i;
for (i = obj -> level - 1; i >= 0; i--)
{
while(cur -> next[i] != NULL && cur -> next[i] -> val < num)
{
cur = cur -> next[i];
}
prevNodes[i] = cur;
}
cur = cur -> next[0];
for (i = 0; i < cur -> maxLeve; i++)
{
prevNodes[i] -> next[i] = cur -> next[i];
}
//判断是否删除最高层
for (i = obj -> level -1; i >= 0; i--)
{
if(obj -> head -> next[i] -> next[i] != NULL)
{
break;
}
obj -> level--;
}
free(cur);
return true;
}
void skiplistFree(Skiplist* obj)
{
if(obj == NULL || obj -> head -> next[0] -> next[0] == NULL)
{
return;
}
SkipNode* cur = obj -> head -> next[0];
SkipNode* tmp = cur -> next[0];
while(cur != NULL)
{
tmp = tmp -> next[0];
free(cur);
cur = tmp;
}
free(obj);
obj = NULL;
}
/**
* Your Skiplist struct will be instantiated and called as such:
* Skiplist* obj = skiplistCreate();
* bool param_1 = skiplistSearch(obj, target);
* skiplistAdd(obj, num);
* bool param_3 = skiplistErase(obj, num);
* skiplistFree(obj);
*/
这道题通俗易懂的来说就是要我们统计出一个链表中,连续节点的区间个数,这个区间里的每个数都必须是nums中的。
int numComponents(struct ListNode* head, int* nums, int numsSize)
{
int* map = (int*)calloc(100000,sizeof(int));
int i,ans = 0;
//统计是否出现
for (i = 0; i < numsSize; i++)
{
map[nums[i]] = 1;
}
struct ListNode* cur = head;
while(cur != NULL)
{
if(map[cur -> val] == 1)
{
while(cur != NULL && map[cur -> val] == 1)
{
cur = cur -> next;
}
ans++;
}
if(cur == NULL)
{
break;
}
cur = cur -> next;
}
return ans;
}
代码如下:
int numComponents(struct ListNode* head, int* nums, int numsSize)
{
int* map = (int*)calloc(100000,sizeof(int));
int i,ans = 0;
bool flag = false;
//统计是否出现
for (i = 0; i < numsSize; i++)
{
map[nums[i]] = 1;
}
struct ListNode* cur = head;
while(cur != NULL)
{
if(map[cur -> val] == 1)
{
if(!flag)
{
ans++;
flag = true;
}
}
else
{
flag = false;
}
cur = cur -> next;
}
return ans;
}
这道题的是让我们拿一个和链表一样大的数组来记录每个元素相对应的下一个更大的元素。
我记得有一次看别人题解是这样说的 "看到下一个更。。"一般来说都用单调栈。
int GetListLenth(struct ListNode* head)
{
if(head == NULL)
{
return 0;
}
int len = 0;
while(head != NULL)
{
len++;
head = head -> next;
}
return len;
}
typedef struct
{
struct ListNode* node;
int index;
}Stack;
int* nextLargerNodes(struct ListNode* head, int* returnSize)
{
int len = GetListLenth(head);
int* ans = (int*)malloc(sizeof(int) * len);
Stack* s = (Stack*)malloc(sizeof(Stack) * (len + 1));
*returnSize = len;
int top = 0,pos = 0,i;
memset(ans,0,sizeof(int) * len);
struct ListNode* cur = head;
//讲第一个节点入栈
s[++top].node = cur;
s[top].index = pos++;
cur = cur -> next;
//遍历链表
while(cur != NULL)
{
//获取栈顶元素
if(cur -> val <= s[top].node -> val)
{
//当前的元素不大于栈顶元素的话,入栈
s[++top].node = cur;
s[top].index = pos;
}
else
{
while(top != 0 && cur -> val > s[top].node -> val)
{
ans[s[top--].index] = cur -> val;
}
//入栈
s[++top].node = cur;
s[top].index = pos;
}
pos++;
cur = cur -> next;
}
return ans;
}
struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead -> next = head;
struct ListNode* prev = newHead;
for (prev; prev != NULL; prev = prev -> next)
{
struct ListNode* end = prev -> next;
int sum = 0;
for(end; end != NULL; end = end -> next)
{
sum += end -> val;
if(sum == 0)
{
prev -> next = end -> next;
}
}
}
return newHead -> next;
}
这个思路就很巧妙,但是用C语言来做就很,你懂的。
首先我们建立一个哈希表,拿前缀和去当key去用,拿node当val。
在遍历第一遍的时候,将前缀和与相对的节点存到哈希表中去,如果前缀和多次出现,只存它最后一次出现的位置。
然后再第二次遍历的时候,同样也用前缀和去遍历,如果发现当前节点的前缀和与哈希表中的前缀和不一致,那么他们中间的节点和就是0.
从上面两张图就能够发现,既然两种情况都可以。
第一个是利用了头节点,假设头节点的前缀和是0.
第二个假如我们不用头节点。它不为前缀和不为0的情况,就会走到节点2上去。
上图中右边的跳了等于白跳,所以应该利用头节点,将其前缀和设置成0.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
#define MAX_SIZE 1001
typedef struct
{
struct ListNode* node;
int prefix;
}Hash;
//如果存在返回位置,不存在则返回合适的位置
bool HashSearch(Hash* map, int size, int target, int* index)
{
int left = 0, right = size - 1;
while(left <= right)
{
int mid = (left + right) / 2;
if(map[mid].prefix < target)
{
left = mid + 1;
}
else if(map[mid].prefix > target)
{
right = mid - 1;
}
else
{
*index = mid;
return true;
}
}
*index = left;
return false;
}
//前缀和是key,node是val
void HahsAdd(Hash* map,int* size, int key, struct ListNode* node)
{
if(*size + 1 >= MAX_SIZE)
{
printf("哈希空间不足!\n");
exit(-1);
}
int index = 0;
if(HashSearch(map,*size,key,&index))
{
//数据有直接覆盖
map[index].node = node;
}
else
{
//没有数据,需要新插入,挪动数据
for (int i = *size; i > index; i--)
{
map[i] = map[i-1];
}
map[index].prefix = key;
map[index].node = node;
(*size)++;
}
}
struct ListNode* removeZeroSumSublists(struct ListNode* head)
{
Hash* map = (Hash*)malloc(sizeof(Hash) * MAX_SIZE);
int mapSize = 0;
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead -> val = 0;
newHead -> next = head;
struct ListNode* cur = head;
int prefixSum = 0;
while(cur != NULL)
{
prefixSum += cur -> val;
//将前缀和为key,node为val入哈希
HahsAdd(map,&mapSize,prefixSum,cur);
cur = cur -> next;
}
// for (int k = 0; k < mapSize; k++)
// {
// printf("key: %d val: %d \n",map[k].prefix,map[k].node->val);
// }
//二次遍历
cur = newHead;
prefixSum = 0;
while (cur != NULL)
{
prefixSum += cur->val;
int index = 0;
if (HashSearch(map, mapSize, prefixSum, &index))
{
struct ListNode* node = map[index].node;
if (node != cur)
{
cur->next = node -> next;
}
}
cur = cur->next;
}
return newHead->next;
}
int* nodesBetweenCriticalPoints(struct ListNode* head, int* returnSize)
{
int* ans = (int*)malloc(sizeof(int) * 2);
*returnSize = 2;
ans[0] = -1;
ans[1] = -1;
if(head == NULL || head -> next == NULL || head -> next -> next == NULL)
{
return ans;
}
struct ListNode* prev = head,*cur = prev -> next, *next = cur -> next;
int min = INT_MAX,max = INT_MIN;
int begin, mid, end,n = 2; //n表示第几位
bool flag = false; //用于标记第一个的开始
while(next != NULL)
{
if((cur -> val > prev -> val && cur -> val > next -> val) || (cur -> val < prev -> val && cur -> val < next -> val))
{
if(flag == false)
{
//begin记录第一个之后就不动了
begin = mid = end = n;
flag = true;
}
else
{
//拿end和mid去比较就能求出最短距离
end = n;
if(end - mid < min)
{
min = end - mid;
}
//mid记得移动
mid = end;
}
}
n++;
prev = cur;
cur = next;
next = next -> next;
}
if(flag == false || begin == end)
{
//说明没有极值或者只有一个极值
return ans;
}
ans[0] = min;
ans[1] = end - begin;
return ans;
}
这道是说给你一个链表数组里面都是升序排序的,然后对其进行排序,最后返回。
最直观的方式就是说可以先将所有的链表挨个拼接起来,然后对整个链表进行排序。
就像下面这个代码,可以用上面第13题中的插入排序也能解答。
struct ListNode* insertionSortList(struct ListNode* head)
{
if(head == NULL || head -> next == NULL)
{
return head;
}
struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
newHead -> next = head;
struct ListNode* cur = head -> next, *prev = head, *tmp = NULL;
while(cur != NULL)
{
if(cur -> val >= prev -> val)
{
//去找当前节点比前一个小的节点。
cur = cur -> next;
prev = prev -> next;
}
else
{
//比前面小的节点。
tmp = newHead;
//找合适的位置
while(tmp -> next -> val < cur -> val)
{
tmp = tmp -> next;
}
prev -> next = cur -> next;
cur -> next = tmp -> next;
tmp -> next = cur;
//cur 继续迭代下去
cur = prev -> next;
}
}
return newHead -> next;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize)
{
struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));
head -> next = NULL;
struct ListNode* cur = head;
int i;
for (i = 0; i < listsSize; i++)
{
struct ListNode* node = lists[i];
while(node != NULL)
{
cur -> next = node;
cur = cur -> next;
node = node -> next;
}
}
head -> next = insertionSortList(head -> next);
return head -> next;
}
当然也可以用归并排序来解答。
//合并两个有序链表
struct ListNode* mergeTwoLists(struct ListNode* a, struct ListNode* b)
{
if(a == NULL || b == NULL)
{
return a == NULL ? b : a;
}
struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
dummy -> next = NULL;
struct ListNode* cur = dummy;
struct ListNode* cur1 = a, *cur2 = b;
while(cur1 != NULL && cur2 != NULL)
{
if(cur1 -> val < cur2 -> val)
{
cur -> next = cur1;
cur1 = cur1 -> next;
}
else
{
cur -> next = cur2;
cur2 = cur2 -> next;
}
cur = cur -> next;
}
cur -> next = cur1 == NULL ? cur2 : cur1;
return dummy -> next;
}
struct ListNode* Merge(struct ListNode** lists, int left, int right)
{
if(left == right)
{
return lists[left];
}
if(left > right)
{
return NULL;
}
int mid = (left + right) / 2;
struct ListNode* leftList = Merge(lists,left, mid);
struct ListNode* rightList = Merge(lists,mid+1, right);
return mergeTwoLists(leftList,rightList);
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize)
{
return Merge(lists,0,listsSize - 1);
}
感觉这道题更像再考排序。