leetcode刷题笔记——分治

leetcode 241
这个题改了几次也看了题解,重点复习

/*

给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。

示例 1:

输入: "2-1-1"
输出: [0, 2]
解释:
((2-1)-1) = 0
(2-(1-1)) = 2
*/
/*
分治 以符号分成左右两边 然后分别对左右两边递归
*/

#include
#include
#include
using namespace std;

class Solution {
public:

    vector<int> diffWaysToCompute(string input) {
        vector<int> result;
        int k;

        for (int i = 0; i < input.size(); i++)
        {
            k = i;
            if (!std::isdigit(input[i]))   //检查是否是数字字符stoi
            {
                break;
            }
        }
        if (k == input.size() - 1)       //如果都是数字字符,没有运算符
        {
            int num = std::stoi(input);
            result.push_back(num);
            return result;
        }

        auto res = diffways(input);
        return res;

    }

    vector<int> diffways(string input)
    {
        vector<int> res;
        int k;
        //结束条件 没有标点符号
        for (int i = 0; i < input.size(); i++)
        {
            k = i;
            if (!std::isdigit(input[i]))
            {
                break;
            }
        }
        if (k == input.size() - 1)
        {
            int num = std::stoi(input);
            res.push_back(num);
        }

        //以符号分开两端 然后分治 递归左右两边
        for (int i = 0; i < input.size(); i++)
        {
            if (input[i] == '+' || input[i] == '-' || input[i] == '*')
            {
                string sleft = input.substr(0, i);
                string sright = input.substr(i + 1);
                auto pre = diffways(sleft);
                auto pos = diffways(sright);

                //这里的循环要注意 一开始没有写循环
                for (int j = 0; j < pre.size(); j++)
                {
                    for (int k = 0; k < pos.size(); k++)
                    {
                        switch (input[i])
                        {
                        case '+':
                            res.push_back(pre[j] + pos[k]);
                            break;
                        case '-':
                            res.push_back(pre[j] - pos[k]);
                            break;
                        case '*':
                            res.push_back(pre[j] * pos[k]);
                            break;
                        }
                    }
                }
            

            }
        }
        return res;
    }
};

leetcode 4
复杂度没达到要求 重点复习

/*
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。

请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:
nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0
示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
/*
我的思路就是先合并然后再找
可是复杂度就超了
所以看了后边的官方题解。
*/
#include
#include
#include
using namespace std;

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        //首先分奇数和偶数 如果是奇数就直接调用下边的函数返回那个就行了
        //如果是偶数 就要返回两个 
        int len = nums1.size() + nums2.size();
        if (len % 2 == 1)
        {
            return getres(nums1,nums2,(len+1)/2);
        }
        else
        {
            auto res1 = getres(nums1, nums2, len / 2);
            auto res2 = getres(nums1,nums2,len/2+1);
            return (res1 + res2) / 2.0;   //这里 一开始写2 错了 直接取整了
        }


    }
    int getres(vector<int>& nums1, vector<int>& nums2, int k)
    {
        int m = nums1.size();
        int n = nums2.size();
        int index1 = 0;
        int index2 = 0;
        while (1)
        {
            //边界情况
            //如果一个数组为空了 也就是到最后一个元素了 那就直接返回另一个数组的第k个
            if (index1 == m)
            {
                return nums2[index2+k-1];
            }
            if (index2 == n)
            {
                return nums1[index1+k-1];
            }
            //如果k 等于1  那就是直接返回这两个数组剩余的最下的那个
            if (k == 1)
            {
                return min(nums1[index1],nums2[index2]);

            }
            int newindex1 = min(index1 + k / 2 - 1,m-1); //以免越界
            int newindex2 = min(index2 + k / 2 - 1, n - 1);

            int p1 = nums1[newindex1];
            int p2 = nums2[newindex2];

            //如果 p2>=p1 则 nums1前边的k/2 -1 个元素去除掉
            if (p1 <= p2)
            {
                //先改变k的值 就是把去除掉的那部分拿走
                //因为上面是有可能越界的 所以这里不能直接k-k/2
                k = k - (newindex1 - index1 + 1);
                //因为去掉的nums1的元素 所以nums2的下标不变 nums1的要加1
                index1 = newindex1 + 1;
            }
            else
            {
                k = k - (newindex2 - index2 + 1);   //就这样一直找 找到k等于1 的时候
                index2 = newindex2 + 1;
            }
        }

    }
};

leetcode 面试36
也是看了题解 重点复习

#include

/*
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
*/
/*
答案来自:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/solution/di-gui-yi-li-jie-by-jameygo/
设:有任意结点 r
step 1 将r的左子树变为有序链表,要输出此有序链表的头尾结点 Lhead、LTail;
step 2 将r的右子树变为有序链表,要输出此有序链表的头尾结点 Rhead、RTail;
step 3 将r结点与左有序链表和右有序两边连接;即将Ltail结点与r->left连接;将r->right 与 Rhead与其连接;
step 4 返回以r结点为根的树的头与尾 :Lhead、RTail
截止条件:r 为叶子结点

*/
//也可以用中序遍历 二叉搜索树中序遍历就是从小到大 中序遍历然后在改地址 组成一个循环链表
// Definition for a Node.
class Node {
public:
    int val;
    Node* left;
    Node* right;

    Node() {}

    Node(int _val) {
        val = _val;
        left = NULL;
        right = NULL;
    }

    Node(int _val, Node* _left, Node* _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};

class Solution {
public:
    Node* treeToDoublyList(Node* root) {
        if (root == NULL)
        {
            return NULL;
        }
        Node* head;  //新建两个节点作为链表的头节点和尾节点
        Node* tail;
        listtree(root,head,tail); //这个主要用到返回的head和tail 用的引用 改变这两个值 返回链表的头和尾
        head->left = tail;   //把链表头尾链接 变成循环链表
        tail->right = head;
        return head;

    }

    //作用是把树排好序 变成链表
    void listtree(Node* r,Node* &head,Node* &tail) //要改变这个head和tail 因为是要用到改变后的值的
    {
        if (r == NULL) {
            return;
        }
        Node* lhead, * ltail, * rhead, * rtail;
        lhead = r;
        if (r->left != NULL) {
            listtree(r->left, lhead, ltail);
            r->left = ltail;
            ltail->right = r;
        }
        rtail = r;
        if (r->right != NULL) {
            listtree(r->right, rhead, rtail);
            r->right = rhead;
            rhead->left = r;
        }
        head = lhead;                //这里每次head tail都记录了变化
        tail = rtail;

    }
};

leetcode 面试39
这个简单一些

/*
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
*/

/*
可以先排序 然后中位数肯定是最多的那个(因为最多的那个超过了一半)
*/
#include
#include
#include
using namespace std;

//104ms
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        auto n = nums.size();
        n = n / 2;
        return nums[n];
    }
};

/*
摩尔投票
两个不一样的遇见 就都去掉
这样最后剩的肯定是最多的
*/

//28ms  
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        auto n = nums.size();
        int res = 0;
        int count = 0;
        for (int i = 0; i < n; i++)
        {
            if (count == 0)
            {
                res = nums[i];
                count++;
            }
            else
            {
                if (res == nums[i])
                {
                    count++;
                }
                else
                {
                    count--;
                }
            }
        }
        return res;
;
    }
};

你可能感兴趣的:(C/C++,数据结构与算法)