面试题-链表相关操作

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList

思想:借用栈先进后出的特性

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> result;
        stack<int> arr;
        ListNode* p=head;
        if(p==NULL)
        {
            return result;
        }
        while(p!=NULL)
        {
            arr.push(p->val);
            p=p->next;

        }
        int len=arr.size();
        for(size_t i=0;i<len;i++)
        {
            result.push_back(arr.top());
            arr.pop();

        }
        return result;
    }
};

convert-sorted-list-to-binary-search-tree
给定元素按升序排序的单个链接列表,将其转换为高度平衡BST。

思想:
这道题是要求把有序链表转为二叉搜索树,和之前那道Convert Sorted Array to Binary Search Tree思路完全一样,只不过是操作的数据类型有所差别,一个是数组,一个是链表。数组方便就方便在可以通过index直接访问任意一个元素,而链表不行。由于二分查找法每次需要找到中点,而链表的查找中间点可以通过快慢指针来操作。找到中点后,要以中点的值建立一个数的根节点,然后需要把原链表断开,分为前后两个链表,都不能包含原中节点,然后再分别对这两个链表递归调用原函数,分别连上左右子节点即可。

class Solution {
public:
    TreeNode *sortedListToBST(ListNode *head) {
        return BST(head,NULL);
    }
    TreeNode *BST(ListNode *head,ListNode *tail)
    {
        if(head == tail)
            return NULL;
        ListNode *s = head;
        ListNode *f = head;
        while(f!=tail && f->next!=tail)
        {
            f = f->next;
            s = s->next;
            if(f!=NULL)
            {
                f=f->next;
            }


        }
        TreeNode *root = new TreeNode(s->val);
        root->left = BST(head,s);
        root->right = BST(s->next,tail);

        return root;
    }
};

给定一个链表和一个值x,对其进行分区,使所有小于x的节点都位于大于或等于x的节点之前。您应该保留两个分区中每个节点的原始相对顺序。例如,给定1->4->3->2->5->2和x=3,返回1->2->2->4->3->5.

思想:
由题意可知:本题要比较大小并排序,所有需要定义一个临时节点遍历链表。(我定义了cur)

要求不改变相对位置的排序,我们利用合并链表的方法,定义两个链表,如果当前值比x小,就将该节点连接到链表1,反之则连接到链表2后边。当链表遍历完结后,将链表1连接到链表2后面,就可以实现要求

这里写图片描述

class Solution {
public:
    ListNode *partition(ListNode *head, int x) {
        if(!head||!head->next) return head;
        ListNode *res1=new ListNode(0);ListNode *p1=res1;
        ListNode *res2=new ListNode(0);ListNode *p2=res2;
        ListNode *cur=head;
        while(cur){
            if(cur->val< x) {p1->next=cur;p1=p1->next;}
            else {p2->next=cur;p2=p2->next;}
            cur=cur->next;
        }
        p2->next=NULL;
        p1->next=res2->next;
        return res1->next;





    }
};

Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given1->2->3->4->5->NULLand k =2,
return4->5->1->2->3->NULL.
旋转链表:

思路:先求出链表的长度,然后将链表连接成一个环。
由于K可能大于链表长度,所以要将k进行取模运算。
连接成环以后,再朝前走len-k步,走到给定K位置的前一个位置处,将其下一个节点设置成头结点,然后将其断开。就是给定要求的链表了。
这里写图片描述

class Solution {
public:
    ListNode *rotateRight(ListNode *head, int k) {
        if(head==nullptr||k==0)
            return head;
        int len=1;
        ListNode *p=head;
        while(p->next){
            //遍历一遍,求出链表长度
            len++;
            p=p->next;
        }
        k=len-k%len;

        p->next=head;//首尾相连
        for(int step=0;step<k;step++){
            p=p->next;//接着往后跑
        }
        head=p->next;//新的首节点
        p->next=nullptr;//断开环
        return head;
    }
};

删除倒数第K个节点

定义两个指针,一个指针,一个慢指针,让快指针先走K-1步,然后快慢指针一起走。当快指针走到结尾时,慢指针刚好走到倒数第K个节点。删除即可。注意考虑删除的是头结点(如果fast先走时,走到尾节点时)

class Solution {
public:
    ListNode *removeNthFromEnd(ListNode *head, int n) {
        if(head==NULL)
        {
            return NULL;
        }
        ListNode* fast=head;
        ListNode* slow=head;

        while(n--)
        {

                fast=fast->next;


        }
        if(fast==NULL)
        {
            return head->next;
        }
        while(fast->next!=NULL)
        {
            slow=slow->next;
            fast=fast->next;
        }
        ListNode*tmp=slow->next;
        slow->next=slow->next->next;
        delete tmp;
        tmp=NULL;
        return head;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值