程序员进阶之算法练习(八十九)leetcode

题目1 组合总和

题目链接
题目大意:
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

题目解析:
题目要找出所有组合,并且一个数字可以无限选,那么可以用这样的枚举方式:
初始化状态,curTarget=target,记录剩下的数字和;
对于数字a[0],不断选择从curTarget减去a[0],直到curTarget<=0截止;
此时再恢复一个a[0],curTarget+=a[0],然后同样方式枚举a[1]、a[2]...

DFS的方式,中间curTarget=0则表示出现一个解,当前栈数字就是答案。


class Solution {
    vector<vector<int>> ans;
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<int> cur;
        while (!ans.empty()) {
            ans.pop_back();
        }
        dfs(cur, candidates, 0, target);
        return ans;
    }
    
    void dfs(vector<int> &cur, vector<int>& candidates, int index, int left) {
        if (left == 0) {
            ans.push_back(cur);
            return ;
        }
        if (index >= candidates.size()) {
            return ;
        }
        if (left >= candidates[index]) {
            cur.push_back(candidates[index]);
            dfs(cur, candidates, index, left - candidates[index]);
            cur.pop_back();
        }
        dfs(cur, candidates, index + 1, left);
    }
    
}leetcode;

题目2 接雨水

题目链接
题目大意:
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6

题目解析:
先找出一个递增的子序列,直到遇到一个数组的最大值;
如何快速计算两个数字之间能乘的雨水?排除法。
矩形,去掉中间数字的和。

最后反着计算,考虑高度相同的情况即可。


class Solution {
public:
    int trap(vector<int>& height) {
        int curHeight = -1, sum = 0, pos = -1, ans = 0;
        for (int i = 0; i < height.size(); ++i) {
            if (height[i] > curHeight) {
                ans += curHeight * (i - pos - 1) - sum;
                curHeight = height[i];
                sum = 0;
                pos = i;
            }
            else {
                sum += height[i];
            }
        }
        int highPos = pos;
        curHeight = -1, sum = 0,
        pos = height.size();
        for (int i = height.size() - 1; i >= highPos && i >= 0; --i) {
            if (height[i] >= curHeight) {
                ans += curHeight * (pos - i - 1) - sum;
                curHeight = height[i];
                sum = 0;
                pos = i;
            }
            else {
                sum += height[i];
            }
        }
        return ans;
    }
}lc;

题目3 全排列

题目链接
题目大意:
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]
输出:[[1]]

提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同

题目解析:
只要完成1到n的全排列,那么输出的时候把1到n换成数组元素nums[1]到nums[n]就可以得到全排列;
全排列的做法:
深度优先遍历(DFS),1、2、3、、、n,每个数字有取和不取的选择;
因为数字不相同,所以不会出现不一致的情况;(每一位至少存在不一样的数字)
用递归更容易实现。


class Solution {
public:
    int vis[N];
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > ans;
        memset(vis, 0,  sizeof(int) * nums.size());
        vector<int> tmp;
        look(ans, nums, tmp, 0);
        return ans;
    }
    
    void look(vector<vector<int> > &ans, vector<int> &num, vector<int> &tmp, int count) {
        if (count == num.size()) {
            ans.push_back(tmp);
            return ;
        }
        int id;
        for (id = 0; id < num.size(); ++id) {
            if (!vis[id]) {
                vis[id] = 1;
                tmp.push_back(num[id]);
                look(ans, num, tmp, count + 1);
                tmp.pop_back();
                vis[id] = 0;
            }
        }
    }
}leetcode;

题目4 字母异位词分组

题目链接
题目大意:
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
["ate","eat","tea"],
["nat","tan"],
["bat"]
]
说明:

所有输入均为小写字母。
不考虑答案输出的顺序。

题目解析:
字母异位词相当于每个字符出现的次数一致,那么字符串中位置信息是无用的,可以统计每个字符串中字母的数量,每个字符可以转为长度为26的数组;
接下来用排序的方式,将所有的数组进行排序,这样数组一样的就会变得相邻,最后遍历数组即可。

思考:
hash的做法,将每个字符串排序,从小到大,然后用hash的方法将字符串映射为整数;(unorder_map + string)

class Solution {
public:
   vector<vector<string>> groupAnagrams(vector<string>& strs) {
       int n = strs.size();
       Node dot[n];
       for (int i = 0; i < n; ++i) {
           memset(dot[i].cnt, 0, sizeof(dot[i].cnt));
           for (int j = 0; j < strs[i].length(); ++j) {
               dot[i].cnt[strs[i][j] - 'a']++;
           }
           dot[i].index = i;
       }
       sort(dot, dot + n);
       vector<vector<string>> ret;
       vector<string> tmp;
       tmp.push_back(strs[dot[0].index]);
       for (int i = 1; i < n; ++i) {
           if (!dot[i].isEqual(dot[i - 1])) {
               ret.push_back(tmp);
               tmp.clear();
           }
           tmp.push_back(strs[dot[i].index]);
       }
       ret.push_back(tmp);
       return ret;
   }
}leetcode;

题目5 最大子数组和

题目链接
题目大意:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组 是数组中的一个连续部分。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:

输入:nums = [1]
输出:1
示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

题目解析:
暴力的做法,枚举每个子区间[i, j],算出每个区间的和,总的复杂度是O(N ^ 2);

动态规划的做法:
1、子问题拆解,dp[i]表示前i个数字中,区间以第i个数字结尾的最大和;
2、状态转移,两个选择,要么取a[i-1]的区间,要么不取前i-1个字数字,得状态转移方程:dp[i] = max(dp[i - 1] + a[i], a[i]);
复杂度为O(N);

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int ret = nums[0], n = nums.size();
        vector<int> dp(n);
        dp[0] = nums[0];
        for (int i = 1; i < n; ++i) {
            dp[i] = max(dp[i - 1] + nums[i], nums[i]);
            ret = max(ret, dp[i]);
        }
        return ret;
    }
}leetcode;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容