算法&数据结构学习(2) 剑指offer刷题笔记(4)

面试题20. 表示数值的字符串

在这里插入图片描述
本题的题目描述比较简单,例子比较少,解法也有多种,比如DFA确定有限状态机(然鹅我不会,回头再去了解了解),那咋办呢,有个投机取巧的方法就是正则表达式匹配直接调用库函数,那就不说了。正常的解法那就按照题目的意思和规则办,有啥情况就分析啥情况,走一步看一步就完事。
代码如下(思路在注释):

class Solution {
public:
    bool isNumber(string s) {
        if(s.empty() || s==" ") return false;
        int l =s.find_first_not_of(' ');//去掉前边的空格
        int start = l;
        int r =s.find_last_not_of(' ');//去掉后边的空格
        bool numflag = false;//数值标记
        bool eflag = false;//指数标记
        bool dotflag = false;//点标记
        for(;l<=r; ++l)
        {
            if(isdigit(s[l]))
                numflag = true;
            else if(s[l]=='.')
            {
                //.之前不能出现e或者.
                if(dotflag || eflag)
                    return false;
                dotflag = true;
            }else if(s[l]=='e' || s[l]=='E')
            {
                //E之前不能出现E,且必须有数字
                if(eflag || !numflag)
                    return false;
                eflag = true;
                numflag = false;//重置数字标志
            }else if(s[l]=='+' || s[l]=='-')
            {
                //+-号必须在第一个位置或者在E之后的第一个位置
                if(l!=start && s[l-1]!='e' && s[l-1]!='E')
                    return false;
            }else
                //其余不合法字符
                return false;
        }
        return numflag;
    }
};

面试题21. 调整数组顺序使奇数位于偶数前面

在这里插入图片描述
解法1:双指针

class Solution {
public:
    vector<int> exchange(vector<int>& nums) {
        //双指针法
        int lo = 0, hi = nums.size()-1;
        while(lo<hi)
        {
            while(lo<hi && (nums[lo]&1))
                ++lo;
            while(lo<hi && (nums[hi]&1)==0)
                --hi;
            swap(nums[lo],nums[hi]);
        }
        return nums;
    }
};

解法2:快慢指针

class Solution {
public:
    vector<int> exchange(vector<int>& nums) {
        //快慢指针
        int slow = 0, fast = 0;
        while(fast<nums.size())
        {
            if(nums[fast]&1)
                swap(nums[slow++],nums[fast]);
            ++fast;
        }
        return nums;
    }
};

面试题22. 链表中倒数第k个节点

在这里插入图片描述
思路:1、最直接的想法肯定是遍历一遍链表,然后统计节点个数n,然后从头节点开始顺序遍历,向前进n-k个节点,即到达倒数第k个节点,这样的情况下需要顺序遍历两次链表,因此时间复杂度有O(n^2),效率是较低的;2、链表的遍历思想中很容易想到一种思路,即双指针或者是快慢指针,本题可以引用双指针,初始化两个指针起始都指向头指针,然后指针p2先走k步,然后p1,p2在同时前进直到p2到达链表尾端,此时p1即倒数第k个节点,这样实际上只需要遍历一遍链表,即p2从头走到了尾,因此时间复杂度降低到O(n)。

class Solution {
public:
    ListNode* getKthFromEnd(ListNode* head, int k) {
        auto p1 = head;
        auto p2 = head;
        while(k--)
        {
            p2 = p2->next;
        }
        while(p2)
        {
            p2=p2->next;
            p1=p1->next;
        }
        return p1;
    }
};

面试题24. 反转链表在这里插入图片描述

解法1:递归

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //递归法
        if(!head || !head->next) return head;
        ListNode* newhead = reverseList(head->next);
        head->next->next = head;
        head->next = nullptr;
        return newhead;
    }
};

解法2:双指针

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //双指针
        ListNode* pre = nullptr, *cur = head;
        while(cur)
        {
            auto post = cur->next;
            cur->next = pre;
            pre = cur;
            cur = post;
        }
        return pre;
    }
};

面试题25. 合并两个排序的链表在这里插入图片描述

思路:整体思想和归并排序一样,定义一个伪头部dummy_head与一定前驱节点pre,然后对l1和l2两个链表进行遍历归并,直至某一链表值为空,最后再将非空的链表接上即可。

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        //伪头结点法
        ListNode* dummy_head = new ListNode(-1);
        auto pre = dummy_head;
        while(l1 && l2)
        {
            if(l1->val<=l2->val)
            {
                pre->next = l1;
                pre = l1;
                l1 = l1->next;
            }else
            {
                pre->next = l2;
                pre = l2;
                l2 = l2->next;
            }
        }
        if(!l1) pre->next = l2;
        else pre->next = l1;
        return dummy_head->next;
    }
};

面试题26. 树的子结构

在这里插入图片描述
解题思路:递归求解,1、定义一个辅助函数helper(),去判断两棵树是否相等;2、对树A进行遍历 ,以每一个节点为根节点的树与树B是否相等,如果存在相等,即B为A的子树。
代码如下:

class Solution {
public:
    bool isSubStructure(TreeNode* A, TreeNode* B) {
        //递归
        if(!B || !A) return false;
        if(A->val==B->val)
            if(helper(A,B)) return true;
        return isSubStructure(A->left,B) || isSubStructure(A->right,B);
    }
private:
    bool helper(TreeNode* A, TreeNode* B)
    {
        if(!B) return true;
        if(!A && B) return false;
        if(A->val!=B->val) return false;
        return helper(A->left,B->left) && helper(A->right,B->right);
    }
};

面试题27. 二叉树的镜像(翻转二叉树)

在这里插入图片描述
解法1:递归

class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        //递归法
        if(!root) return root;
        auto left = mirrorTree(root->left);
        auto right = mirrorTree(root->right);
        root->left = right;
        root->right = left;
        return root;
    }
};

解法2:辅助队列

class Solution {
public:
    TreeNode* mirrorTree(TreeNode* root) {
        //队列
        if(!root) return root;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty())
        {
            auto cur = q.front();
            q.pop();
            auto tmp = cur->left;
            cur->left = cur->right;
            cur->right = tmp;
            if(cur->left) q.push(cur->left);
            if(cur->right) q.push(cur->right);
        }
        return root;
    }
};

今日刷题笔记顺利完成,今日更多的题目是关于链表与树的内容,因此有许多的递归应用。同时也能感觉到链表中常用的方法:双指针可以优化链表的遍历或操作。明日继续!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值