天天看点

反转链表,基础栈练习,贪心

今天先来三道力扣题

第一题:

原题链接如下

https://leetcode-cn.com/problems/palindrome-linked-list/

反转链表,基础栈练习,贪心

一道链表题,方法有多种。我最开始做的方法是用数组记录链表的每个结点,将链表转换成数组,然后就用数组的方法去写。 

bool isPalindrome(struct ListNode* head){
    int a[100000],k=0;
    while(head)
    {
        a[k++] = head->val;
        head = head->next;
    }
    int i=0,j=k-1;
    while(i<j)
    {
        if(a[i]!=a[j])
        return false;
        i++;
        j--;
    }
    return true;
}
           

但还有空间复杂度更低的方法,直接对链表进行操作,将链表后半部分反转过来,然后进行匹配。

那么如何对链表后半部分进行反转呢,首先得找到链表中间的位置,这里我们考虑用快慢指针法,定义一个慢指针slow和一个快指针fast,慢指针移动一个结点时快指针移动两个结点,这样当快指针遍历到链表末尾时,慢指针就在链表的中间位置。(注意奇偶问题)
while(fast)
    {
        slow = slow->next;
        fast = fast->next ? fast->next->next : fast->next;
    }
           
反转链表,基础栈练习,贪心
 如图是slow指针和fast指针的指向,接着我们要更改后半段链表指针的指向,这里我们需要借助另外两个指针(可以定义为pre和temp),为什么要两个指针呢?首先我们需要更改slow的指向吧,令它指向NULL,然后slow需要移动到下一个结点,然后再指向上一个结点。可这时slow的指向已经改变了,因此我们需要定义一个指针变量temp率先移动到slow的下一个结点,再更改slow的指向,我们可以用pre表示slow的上一个结点,pre初始为NULL。
反转链表,基础栈练习,贪心

更改指向后使pre移动到slow,再使slow移动到temp就行了,重复这个过程到链表尾部。

反转链表,基础栈练习,贪心

 最后就是这样。

代码如下:

while(slow)
    {
        struct ListNode* temp = slow->next;     //移动到slow的下一个结点
        slow->next = pre;           //改变slow的指向
        pre = slow;                 //上一个结点移动到当前位置
        slow = temp;                //slow移动到temp
    }
           

 最后只需要同时遍历头结点和pre就行了判断是否相等。

完整代码如下:

bool isPalindrome(struct ListNode* head){
    struct ListNode* slow=head,*fast=head,*pre = NULL;
    while(fast)
    {
        slow = slow->next;
        fast = fast->next ? fast->next->next : fast->next;
    }
    while(slow)
    {
        struct ListNode* temp = slow->next;     //移动到slow的下一个结点
        slow->next = pre;           //改变slow的指向
        pre = slow;                 //上一个结点移动到当前位置
        slow = temp;                //slow移动到temp
    }
    while(head && pre)
    {
        if(head->val != pre->val)
        return false;
        head = head->next;
        pre = pre->next;
    }
    return true;
}
           

第二题属于栈的题目。

https://leetcode-cn.com/problems/valid-parentheses/

反转链表,基础栈练习,贪心

括号匹配以前做过类似的题。

具体思路是将括号的左半部分压入栈中,栈顶元素碰到匹配的右括号时,将栈顶元素弹出栈,若遇到的右括号 与栈顶元素不匹配或栈内没有元素则返回false。最后判断站内是否含有元素,若含有则返回false,没有则返回true。

代码如下:

bool isValid(char * s){
    char a[10001];
    int i,len = strlen(s);
    int top = 0;
    for(i=0;i<len;i++)
    {
        if(s[i]=='('||s[i]=='['||s[i]=='{')
        a[++top] = s[i];
        else if(a[top]=='('&&s[i]==')'||a[top]=='['&&s[i]==']'||a[top]=='{'&&s[i]=='}')
        top--;
        else
        return false;
    }
    if(top==0)
    return true;
    return false;
}
           

第三题了!

https://leetcode-cn.com/problems/valid-parenthesis-string/

反转链表,基础栈练习,贪心

 咋一看又是一道括号匹配的题,先入为主就想用栈来写了。

我先提供一种用栈的方法,由于*可以变成’(‘或者’)‘或者空字符,这里我们考虑用两个栈,一个栈用来存’(‘一个用来存’*‘,当碰到’)‘时优先将存储’(‘的栈顶元素弹出,若存储'('的栈内没有元素,则弹出存储‘*’的栈顶元素(  视作‘*“变成了’('  ),若两个栈内都没有元素,则说明右括号无法匹配完全,返回false,若整个过程都能匹配,还需判断‘(’能否全部匹配,从后往前按照相同的方法再遍历一遍就行了。

参考代码入下:

bool checkValidString(char * s){
    int a[101],b[101];
    int len = strlen(s),i,top1=0,top2=0;
    for(i=0;i<len;i++)
    {
        if(s[i]=='(')
        a[++top1] = i;
        else if(s[i]=='*')
        b[++top2] = i;
        else if(s[i]==')'&&top1>0)
        top1--;
        else if(s[i]==')'&&top2>0)
        top2--;
        else
        return false;
    }
    top1=0,top2=0;
    for(i=len-1;i>=0;i--)
    {
        if(s[i]==')')
        a[++top1] = i;
        else if(s[i]=='*')
        b[++top2] = i;
        else if(s[i]=='('&&top1>0)
        top1--;
        else if(s[i]=='('&&top2>0)
        top2--;
        else
        return false;
    }
    return true;
}
           

其实这题还有更简单的方法,用贪心解决,

设想一下,我们可以用一个变量来表示未匹配的左括号数,当遇到‘(’时使该变量加1,遇到‘)’时使该变量减1,那么遇到‘*'时该怎么办呢?由于’*‘可能变成’(‘可能变成’)‘还可能变成空字符,对该变量的影响分别就是加1,减1,不变。因此我们可以定义两个变量来确定这个范围的最大值和最小值,在这过程中出现范围最大值小于0的情况,则直接返回false(表示最左端为’)‘无法完成匹配),若出现范围最小值小于0的情况则最小值变成0(未匹配的括号数不能为负数),最后进行判断,如果整个范围包括0(即最小值为0),说明整个过程能完成匹配。
bool checkValidString(char * s){
    int len=strlen(s);
    int min=0,max=0,i;
    for(i=0;i<len;i++)
    {
        if(s[i]=='(')
        {
            min++;
            max++;
        }
        else if(s[i]==')')
        {
            min--;
            max--;
            if(min<0)
            min=0;
            if(max<0)
            return false;
        }
        else
        {
            min--;
            max++;
            if(min<0)
            min=0;
        }
    }
    if(min==0)
    return true;
    return false;
}
           

终于写完啦!!!

文中代码可能写的冗长,我尽量用简单的方式呈现给大家!希望大家不要建议。

与君共勉!

看到这里你也累了吧,不妨三连一波!!!

继续阅读