leetcode_链表

题目

1:合并两个链表 1669
2:相交链表 023
3: 旋转链表 061
4:奇偶链表 328
5: 环形链表 141
6: 分割链表 86
7:无重复最长字符串 3

经验

1:要有头指针,方便处理空链表情况。
2:合并链表关键是确定条件,从哪插入,从哪删除。
3:单链表走了就不回来了,就要判断是否需要一个变量保存所需要的节点。
4:如果只用一个变量表示单链表,那么当链表走向下一个时,仅仅凭单个变量是再也找不回原本的链表,所以记得多指针。
5:哈希表的原理是一个key值对应一个valve,然后通过一个key值可以直接找到value。对于相交链表,暴力解法是mn次,但对于哈希表,由于其特殊性,所以只要比较m1次,但难度来到了哈希表的建立。
6:头节点便于单链表为空时的处理,但是要确定头节点指向的是单链表的开始。
7:快慢指针,快指针走两步,满指针走一步,如果说有环形链表,那么快慢指针最终会重叠,比如题目5的解法。快慢指针也可以用来找到链表中的中点。

合并两个链表 1669

给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。

题目描述
请你将 list1 中下标从 a 到 b 的全部节点都删除,并将list2 接在被删除节点的位置。
输入:list1 = [0,1,2,3,4,5], a = 3, b = 4, list2 = [1000000,1000001,1000002]
输出:[0,1,2,1000000,1000001,1000002,5]
解释:我们删除 list1 中下标为 3 和 4 的两个节点,并将 list2 接在该位置。上图中蓝色的边和节点为答案链表。
输入:list1 = [0,1,2,3,4,5,6], a = 2, b = 5, list2 = [1000000,1000001,1000002,1000003,1000004]
输出:[0,1,1000000,1000001,1000002,1000003,1000004,6]
解释:上图中蓝色的边和节点为答案链表。

代码
`struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2)
{
int i = 0;
struct ListNode* PHead = (struct ListNode)malloc(sizeof(struct ListNode));
struct ListNode
p1 = list1;
struct ListNode* p2 = NULL;
struct ListNode* temp = list2;
PHead->next = NULL;
PHead->next = p1;

if ((a < 0) || (b < 0) || (a > b))
{
    return NULL;
}

//找到list1 a-1 点
for (; (i < a - 1) && (p1 != NULL) ; i = i + 1)
{
    p1 = p1->next;
}

//找到b+1点
p2 = p1->next;
for (; (i <= b - 1 ) && (p2 != NULL) ; i = i + 1)
{
    p2 = p2->next;
}


p1->next = temp;
while(NULL != temp->next)
{
    temp = temp->next;
}
temp->next = p2;

return PHead->next;

}`

相交链表

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

示例 1:

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。

本题较好的方法是采用哈希表,
`struct ListNode getIntersectionNode(struct ListNode headA, struct ListNode headB)
{
struct ListNode PHeadA;
struct ListNode PHeadB;
struct ListNode
PA;
struct ListNode
PB;
struct ListNode
Result;

PHeadA.next = NULL;
PHeadB.next = NULL;
PA = NULL;
PB = NULL;
Result = NULL;

PHeadA.next = headA;
PHeadB.next = headB;
PA = PHeadA.next;
PB = PHeadB.next;

if (NULL == PA || NULL == PB)
{
    return Result;
}
while(NULL != PA)
{
    while(NULL != PB)
    {
        if (PA == PB)
        {
            Result = PA;
            return Result;
        }
        PB = PB->next;
    }
    PB = PHeadB.next;
    PA = PA->next;
}


 return Result;

}`

旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
示例 2:

输入:head = [0,1,2], k = 4
输出:[2,0,1]

`struct ListNode* rotateRight(struct ListNode* head, int k)
{
struct ListNode* PPre;
struct ListNode* PMid;
struct ListNode PHead;
int ListNumber = 0;//链表数目
int RotateNumber = 0;

if (NULL == head)
{
    return NULL;
}
PHead.next = NULL;
PHead.next = head;
PPre = &PHead;
PMid = PHead.next;

//计算链表节点数目和使之成为循环链表
while(PMid->next != NULL)
{
    ListNumber = ListNumber + 1;
    PMid = PMid->next;
}
ListNumber = ListNumber + 1;
PMid->next = PHead.next;//使之成为循环链表

RotateNumber = k % ListNumber;//从头结点要转移的数目
//printf("%d", ListNumber);
RotateNumber = ListNumber - RotateNumber;
PPre = PMid;
PMid = PHead.next;

for (int i = 0; i < RotateNumber; i = i + 1)
{
    PMid = PMid->next;
    PPre = PPre->next;
}
PPre->next = NULL;

return PMid;

}
`

奇偶链表

给定单链表的头节点 head ,将所有索引为奇数的节点和索引为偶数的节点分别组合在一起,然后返回重新排序的列表。

第一个节点的索引被认为是 奇数 , 第二个节点的索引为 偶数 ,以此类推。

请注意,偶数组和奇数组内部的相对顺序应该与输入时保持一致。

你必须在 O(1) 的额外空间复杂度和 O(n) 的时间复杂度下解决这个问题。

示例 1:

输入: head = [1,2,3,4,5]
输出: [1,3,5,2,4]
示例 2:

输入: head = [2,1,3,5,6,4,7]
输出: [2,3,6,7,1,5,4]

`struct ListNode* oddEvenList(struct ListNode* head)
{
struct ListNode* ListNode = NULL;
struct ListNode* TempListNode = NULL;
struct ListNode OddHead;//偶链表头节点
struct ListNode EvenHead;//奇链表头节点
struct ListNode* OddListNode = NULL;//偶链表
struct ListNode* EvenListNode = NULL;//奇链表
int i = 1;

EvenHead.next = NULL;
OddHead.next = NULL;    
ListNode = head;
if (NULL == ListNode)
{
    return ListNode;
}

EvenHead.next = ListNode;
EvenListNode = EvenHead.next;
ListNode = ListNode->next;
OddHead.next = ListNode;
OddListNode = OddHead.next;
if (NULL == OddListNode)
{
    return EvenListNode;
}
ListNode = ListNode->next;

while(NULL != ListNode)
{
    if (1 == (i % 2))
    {
        EvenListNode->next = ListNode;
        EvenListNode = EvenListNode->next;
    }
    else  
    {
        OddListNode->next = ListNode;
        OddListNode = OddListNode->next;            
    }

    ListNode = ListNode->next;
    i = i + 1;
}

EvenListNode->next = OddHead.next;
OddListNode->next = NULL;

return EvenHead.next;

}`

环形链表

本题可以采用快慢指针,也可以采用哈希表,过一个节点,就把该元素送入哈希表,如果已经存在,那么就是环形链表,如果不存在,那么就不是。
我原本采用暴力解法,每一个节点就走一遍链表,如果会相等,就是环形的,但是这样时间复杂度达到O(N^2),太高了,超过时间了。

`bool hasCycle(struct ListNode head)
{
struct ListNode
PFast = NULL;
struct ListNode* PSlow = NULL;

if (head == NULL)
{
    return false;
}
if (NULL == head->next)
{
    return false;
}
PFast = head->next;
PSlow = head;

while(PSlow != PFast)
{
    if (NULL == PFast)
    {
        return false;
    }
    if (NULL == PFast->next)
    {
        return false;
    }

    PFast = PFast->next->next;
    PSlow = PSlow->next;
}

return true;

}`

分割链表

双指针,创造两个链表,小于x的就在左边,大于等于x在右边。发现遍历一个指针就可以了,不需要pleft和pright,当时想,
如果pleft指向的那个结构体next被更改了,那么接下来要怎么走呢,然后pright。后面仔细再想一下,遍历到那个点的时候,pleft那个点
的next没有被更改,只是上面要指向它的那个点被更改了。

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

示例 1:

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]
示例 2:

输入:head = [2,1], x = 2
输出:[1,2]

提示:
链表中节点的数目在范围 [0, 200] 内
-100 <= Node.val <= 100
-200 <= x <= 200

`/**

  • Definition for singly-linked list.

  • struct ListNode {

  • int val;
    
  • struct ListNode *next;
    
  • };
    /
    struct ListNode
    partition(struct ListNode* head, int x)
    {
    if (NULL == head)
    {
    return head;
    }
    struct ListNode* PLessHead = NULL;
    struct ListNode* PLess = NULL;
    struct ListNode* PGreterHead = NULL;
    struct ListNode* PGreter = NULL;
    struct ListNode* PLeft = NULL;
    struct ListNode* PRight = head;

    while(NULL != PRight)
    {
    PLeft = PRight;
    PRight = PRight->next;

     if (PLeft->val < x)
     {
         if (NULL == PLessHead)
         {
             PLessHead = PLeft;
             PLess = PLessHead;
         }
         else
         {
             PLess->next = PLeft;
             PLess = PLess->next;
         }
     }
     else
     {
         if (NULL == PGreterHead)
         {
            PGreterHead = PLeft;
            PGreter = PGreterHead;
         }
         else
         {
             PGreter->next = PLeft;
             PGreter =  PGreter->next; 
         }
     }
    

    }

    if (NULL == PLessHead)
    {
    PGreter->next = NULL;
    return PGreterHead;
    }
    else
    {
    PLess->next = PGreterHead;

      if (NULL != PGreter)
      {
         PGreter->next = NULL;
      }
      return PLessHead;
    

    }
    }`

无重复字符的最长子串:3

  1. 无重复字符的最长子串
    示例 1:

输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成
'int lengthOfLongestSubstring(char* s)
{

if (*s == '\0')
{
    return 0;
}
if ((*s != '\0') && (*(s + 1) == '\0'))
{
    return 1;
}

char* str = s;
char* pre = str;
char* mid = str;
char* j = pre;

int maxlen = 0;
int currlen = 1; //判决完成后,该点拥有的不重复字符串长度
int len = 0;

while((*(str + 1)) != '\0')
{
    mid = mid + 1;
    len = 1;

    for(j = pre; j != mid; j = j + 1)
    {
        if ((*j) == (*mid))
        {
            pre = j + 1;

            if (pre == mid)
            {
                currlen = 1;
            }
            else
            {
                currlen = currlen - len + 1;
            }

            break;
        }

        len = len + 1;
    }

    if (j == mid)//没有遇到重复点的情况
    {
        currlen = currlen + 1;
    }
    if (maxlen < currlen)
    {
        maxlen = currlen;
    }

    str = str + 1;
    printf("%d\n", maxlen);
}

return maxlen;

}'

未完待续

posted on 2024-02-21 17:41  我们的歌谣  阅读(3)  评论(0编辑  收藏  举报

导航