leetcode刷題筆記——分治

leetcode 241
這個題改了幾次也看了題解,重點複習

/*

給定一個含有數字和運算符的字符串,爲表達式添加括號,改變其運算優先級以求出不同的結果。你需要給出所有可能的組合的結果。有效的運算符號包含 +, - 以及 * 。

示例 1:

輸入: "2-1-1"
輸出: [0, 2]
解釋:
((2-1)-1) = 0
(2-(1-1)) = 2
*/
/*
分治 以符號分成左右兩邊 然後分別對左右兩邊遞歸
*/

#include<iostream>
#include<string>
#include<vector>
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<iostream>
#include<vector>
#include<algorithm>
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<iostream>

/*
輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的循環雙向鏈表。要求不能創建任何新的節點,只能調整樹中節點指針的指向。
*/
/*
答案來自: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<iostream>
#include<vector>
#include<algorithm>
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;
;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章