1.给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
输入:[1,2,3,4,5]
输出:此列表中的结点 3 (序列化形式:[3,4,5])
返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。
输入:[1,2,3,4,5,6]
输出:此列表中的结点 4 (序列化形式:[4,5,6])
解法思路:先求出单链表的长度length,再定义一个指针初识指向单链表的头部,让指针走length/2步,即为所求。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int Getlength(struct ListNode* head)
{
int count = 0;
if(head==NULL)
{
return 0;
}
struct ListNode* cur=head;
while(cur!=NULL)
{
count++;
cur=cur->next;
}
return count;
}
struct ListNode* middleNode(struct ListNode* head) {
if(head==NULL)
{
return NULL;
}
int k = Getlength(head);
int step = k/2;
struct ListNode* middle = head;
while(step)
{
middle=middle->next;
step--;
}
return middle;
}
2.删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
解法思路:定义一个指针cur指向链表的第二个节点,指针prev初始值为NULL,
只要cur不空,就遍历整个链表,同时cur 与 prev分别向后走一步。若遇到要删除的值,就进行单链表的删除操作。若还未遇到,就一直向后遍历,直到cur为NULL。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val) {
if(head == NULL)
{
return NULL;
}
struct ListNode* cur = head->next ;
struct ListNode* prev = head;
while(cur!=NULL)
{
if(cur->val != val)
{
prev = cur;
cur = cur->next;
}
else
{
struct ListNode* old_cur = cur;
cur = cur->next;
prev->next = cur;
free(old_cur);
}
}
struct ListNode* newHead = head;
if(head->val == val)
{
newHead = head->next;
free(head) ;
}
return newHead;
}
3.反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
解法思路:可以对旧链表进行头删操作,然后将删除的节点头插在新链表中,最后返回新链表的头结点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
if(head == NULL)
{
return NULL;
}
struct ListNode* newHead = NULL;
struct ListNode* node ;
while(head != NULL)
{
//对旧链表做头删操作
node = head ;
head = head->next;
//把删掉的节点头插在新链表中
node->next = newHead;
newHead = node ;
}
return newHead;
}
4.输入一个链表,输出该链表中倒数第k个结点。
解法思路:定义两个指针fast与slow,先让fast走k步,再让两个指针每次走一步,直到fast为NULL,则slow指向的即为所求。
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
ListNode* fast = pListHead;
ListNode* slow = pListHead;
//先让fast走
while(k)
{
fast = fast->next;
k--;
}
//再让两个指针每次走一步
while(fast!=NULL)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
5.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
解法思路:定义两个指针与一个新链表的头尾指针。让两个指针分别指向两个链表。逐一的进行值比较,然后将节点插入新的链表的末端。最后返回新链表的头指针。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
if(l1 == NULL)
{
return l2;
}
if(l2 == NULL)
{
return l1;
}
struct ListNode* p1 = l1;
struct ListNode* p2 = l2;
struct ListNode* r = NULL; //新链表的头
struct ListNode* rtail = NULL; //新链表的尾
while(p1 && p2)
{
if(p1->val <= p2->val)
{
if(rtail == NULL)
{
r = rtail = p1;
}
else
{
rtail->next = p1;
rtail = rtail->next;
}
p1 = p1->next;
}
else
{
if(rtail == NULL)
{
r = rtail = p2;
}
else
{
if(rtail == NULL)
{
r = rtail = p2;
}
else
{
rtail->next = p2;
rtail = p2;
}
}
p2 = p2->next;
}
}
if(p1 == NULL)
{
rtail->next = p2;
}
if(p2 == NULL)
{
rtail->next = p1;
}
return r ;
}
6.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
给定一个链表的头指针 ListNode* pHead,请返回重新排列后的链表的头指针。注意:分割以后保持原来的数据顺序不变。
解法思路:将链表分割成三部分,然后进行遍历,按要求插入即可。
ListNode* partition(ListNode* pHead, int x) {
// write code here
if(pHead == NULL)
{
return NULL;
}
//将链表分割成三部分,小,等于,大
ListNode* lt = NULL; //小的部分的头
ListNode* ltail = NULL ;//小的部分的尾
ListNode* eq = NULL ; //相等的部分的头
ListNode* eqtail = NULL;//相等的部分的尾
ListNode* gt = NULL; //大的部分的头
ListNode* gtail = NULL ;//大的部分的尾
ListNode* cur = pHead;
while(cur != NULL)
{
if(cur->val < x)
{
if(lt == NULL)
{
lt = ltail = cur;
}
else
{
ltail->next = cur;
ltail = ltail->next;
}
}
else if(cur->val == x)
{
if(eq == NULL)
{
eq = eqtail = cur;
}
else
{
eqtail->next = cur ;
eqtail = eqtail->next ;
}
}
else
{
if(gt == NULL)
{
gt = gtail = cur;
}
else
{
gtail->next = cur;
gtail = gtail->next;
}
}
cur = cur->next ;
}
return pHead;
}
7.编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:
在c1处相交,则返回c1的地址。
解法思路:分别求出两个链表的长度len1和len2,定义两个指针longer与shorter,先让长的走两者长度之差步,以保证两个指针的相对位置一样。然后循环遍历,只要节点的位置不同则继续向后走,直到节点地址相等时跳出循环并返回此相交节点的地址。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int Getlength(struct ListNode* head)
{
int count = 0 ;
struct ListNode* cur = head;
while(cur!=NULL)
{
count++;
cur = cur->next;
}
return count;
}
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(headA == NULL)
{
return NULL;
}
if(headB == NULL)
{
return NULL;
}
int len1 = Getlength(headA) ;
int len2 = Getlength(headB) ;
struct ListNode* longer ;
struct ListNode* shorter;
int dif; //长度之差
if(len1 >= len2)
{
longer = headA;
shorter = headB;
dif = len1 - len2;
}
else
{
longer = headB;
shorter = headA;
dif = len2 - len1;
}
//先让长的走dif步保证两者相对距离一样
while(dif)
{
longer = longer->next;
dif--;
}
while(longer!=shorter)
{
longer = longer->next;
shorter = shorter->next;
}
//注意,此处是地址相等即可
if(longer == shorter)
{
return longer;
}
else
return NULL;
}
8.给定一个链表,判断链表中是否有环。
解法思路:利用快慢指针法。具体解法请看以下代码。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
do{
if(fast == NULL)
{
break;
}
fast = fast->next;
if(fast == NULL)
{
break;
}
fast = fast->next;
slow = slow->next;
}while(fast != slow);
if(fast == NULL)
{
return false;
}
else
return true;
}