深度優先搜索解題算法2

題目1:重新安排行程

給定一個機票的字符串二維數組 [from, to],子數組中的兩個成員分別表示飛機出發和降落的機場地點,對該行程進行重新規劃排序。所有這些機票都屬於一個從JFK(肯尼迪國際機場)出發的先生,所以該行程必須從 JFK 出發

如果存在多種有效的行程,你可以按字符自然排序返回最小的行程組合。例如,行程 [“JFK”, “LGA”] 與 [“JFK”, “LGB”] 相比就更小,排序更靠前

示例 1:
輸入: [[“JFK”,“SFO”],[“JFK”,“ATL”],[“SFO”,“ATL”],[“ATL”,“JFK”],[“ATL”,“SFO”]]
輸出: [“JFK”,“ATL”,“JFK”,“SFO”,“ATL”,“SFO”]
解釋: 另一種有效的行程是 [“JFK”,“SFO”,“ATL”,“JFK”,“ATL”,“SFO”]。但是它自然排序更大更靠後

解題思路:深度優先搜索

class Solution {
public:
    unordered_map<string,multiset<string>>map;
    vector<string> res;
    vector<string> findItinerary(vector<vector<string>>& tickets) {
        for(auto& t:tickets){
            map[t[0]].insert(t[1]);
        }
        dfs("JFK");
        return vector<string>(res.rbegin(),res.rend());
    }
    void dfs(string from){
        while(map[from].size()!=0){
            string next = *map[from].begin();
            map[from].erase(map[from].begin());
            dfs(next);
        }
        res.push_back(from);
    }
};

題目2:打家劫舍

在上次打劫完一條街道之後和一圈房屋後,小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之爲“根”。 除了“根”之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之後,聰明的小偷意識到“這個地方的所有房屋的排列類似於一棵二叉樹”。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

示例 1:

輸入: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

輸出: 7 
解釋: 小偷一晚能夠盜取的最高金額 = 3 + 3 + 1 = 7.
示例 2:
輸入: [3,4,5,1,3,null,1]

     3
    / \
   4   5
  / \   \ 
 1   3   1

輸出: 9
解釋: 小偷一晚能夠盜取的最高金額 = 4 + 5 = 9.

解題思路:深度優先搜索和相鄰關係,每個節點有偷和不偷兩種可能,如果偷,則子節點不可以偷,但可以偷孫子節點,如果不偷當前節點,則可以偷子節點.

C++ 參考代碼

class Solution {
public: 
    int rob(TreeNode* root) {
        if(root == NULL) return 0;
        //偷取該節點
        int s1 = root->val;
        if(root->left != NULL){
            s1 += rob(root->left->left) +\
                 rob(root->left->right);
        }
        if(root->right != NULL){
            s1 += rob(root->right->left) +\
                rob(root->right->right);
        }
        //不偷取該節點
        int s0 = 0;
        s0 += rob(root->left) + rob(root->right);
        return max(s0,s1);
    }
};

避免重複計算,用容器保存已經計算過的值

class Solution {
public: 
    unordered_map<TreeNode*,int>map;
    int rob(TreeNode* root) {
        if(root == NULL) return 0;
        //偷取該節點
        if(map.count(root)){
            return map[root];
        }
        int s1 = root->val;
        if(root->left != NULL){
            s1 += rob(root->left->left) +\
                 rob(root->left->right);
        }
        if(root->right != NULL){
            s1 += rob(root->right->left) +\
                rob(root->right->right);
        }
        //不偷取該節點
        int s0 = 0;
        s0 += rob(root->left) + rob(root->right);
        map[root] = max(s0,s1);
        return map[root];
    }
};

題目3:員工的重要性

給定一個保存員工信息的數據結構,它包含了員工唯一的id,重要度 和 直系下屬的id。

比如,員工1是員工2的領導,員工2是員工3的領導。他們相應的重要度爲15, 10, 5。那麼員工1的數據結構是[1, 15, [2]],員工2的數據結構是[2, 10, [3]],員工3的數據結構是[3, 5, []]。注意雖然員工3也是員工1的一個下屬,但是由於並不是直系下屬,因此沒有體現在員工1的數據結構中。

現在輸入一個公司的所有員工信息,以及單個員工id,返回這個員工和他所有下屬的重要度之和。

示例 1:
輸入: [[1, 5, [2, 3]], [2, 3, []], [3, 3, []]], 1
輸出: 11
解釋:
員工1自身的重要度是5,他有兩個直系下屬2和3,而且2和3的重要度均爲3。因此員工1的總重要度是 5 + 3 + 3 = 11

解題思路:通過遍歷找到指定 id 的員工重要性,然後迭加

class Employee {
public:
    int id;
    int importance;
    vector<int> subordinates;
};

class Solution {
public:
    int importance = 0;
    int getImportance(vector<Employee*> employees, int id) {
        int index;
        for(int i = 0;i<employees.size();++i){
            if(employees[i] == nullptr) return importance;
            if(id == employees[i]->id){
                index = i;
                importance += employees[i]->importance;
            }
        }
        for(int i = 0;i<employees[index]->subordinates.size();++i){
            getImportance(employees,employees[index]->subordinates[i]);
        }
        return importance;
    }
};

題目4:火柴正方形

還記得童話《賣火柴的小女孩》嗎?現在,你知道小女孩有多少根火柴,請找出一種能使用所有火柴拼成一個正方形的方法。不能折斷火柴,可以把火柴連接起來,並且每根火柴都要用到。

輸入爲小女孩擁有火柴的數目,每根火柴用其長度表示。輸出即爲是否能用所有的火柴拼成正方形

示例 1:
輸入: [1,1,2,2,2]
輸出: true
解釋: 能拼成一個邊長爲2的正方形,每邊兩根火柴。
示例 2:
輸入: [3,3,3,3,4]
輸出: false
解釋: 不能用所有火柴拼成一個正方形

解題思路:對於給定的若干根火柴,將它們分成四組,每一根火柴恰好屬於其中的一組;每一組火柴的長度之和都相同,等於所有火柴長度之和的四分之一

使用深度優先搜索枚舉出所有的分組情況,並對於每一種情況,判斷是否滿足上述的條件

我們依次對每一根火柴進行搜索,當搜索到第 i 根火柴時,我們可以把它放到四組中的任意一種。對於每一種放置方法,我們繼續對第 i + 1 根火柴進行遞歸搜索。當我們搜索完全部的 N 根火柴後,再判斷每一組火柴的長度之和是否都相同

C++ 參考代碼

class Solution {
public:
    bool makesquare(vector<int>& nums) {
        // 先判斷簡單的情況,如果 nums 元素個數小於4
        int sum = 0;
        for(auto&e:nums){
            sum+=e;
        }
        if(nums.size()<4 || sum % 4 != 0) {
            return false;
        }
        int target = sum / 4;
        // 降序排序
        sort(nums.begin(),nums.end(),greater<int>());
        vector<int>partition(4,0);
        return dfs(target,partition,0,nums);
    }

    bool dfs(int target,vector<int>&partition,int index,vector<int>&nums){
        if(index == nums.size()){
            return (partition[0]==partition[1] &&
                   partition[1] == partition[2] &&
                   partition[2] == partition[3]);
        }
        for(int i = 0;i<4;++i){
            if(partition[i] + nums[index] > target){
                continue;
            }
            partition[i] +=nums[index];
            if(dfs(target,partition, index + 1,nums)){
                return true;
            }
            partition[i] -= nums[index];
        }
        return false;
    }
};

題目5:目標和

給定一個非負整數數組,a1, a2, …, an, 和一個目標數,S。現在你有兩個符號 + 和 -。對於數組中的任意一個整數,你都可以從 + 或 -中選擇一個符號添加在前面。

返回可以使最終數組和爲目標數 S 的所有添加符號的方法數。

示例 1:
輸入: nums: [1, 1, 1, 1, 1], S: 3
輸出: 5
解釋:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
一共有5種方法讓最終目標和爲3。
注意:
數組非空,且長度不會超過20。
初始的數組的和不會超過1000。
保證返回的最終結果能被32位整數存下

解題:暴力搜索法,枚舉出所有的可能性,我們可以把問題看做一個將目標值變爲 0 的情況個數

class Solution {
public:
    int count = 0;
    int findTargetSumWays(vector<int>& nums, int S) {
        int len = nums.size();
        dfs(nums,S,0,len);
        return count;
    }
    void dfs(vector<int>&nums,long target,int i,int len){
        if(i == len && target == 0){
            count++;
            return;
        }
        if(i == len) return;
        dfs(nums,target - nums[i],i+1,len);
        dfs(nums,target + nums[i],i+1,len);
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章