算法每日刷

DAY One: 数组交集问题

题目描述:

给定两个数组,编写一个函数来计算它们的交集。

示例:

//示例1
输入:
	1 2 2 1
	2 2
输出:
	2 2

//示例2
输入:
	4 9 5
	9 4 9 8 4
输出:
	4 9

说明:

  • 可以不考虑输出结果的顺序
  • 重复的元素按重复的次数输出

思路:

如果使用双重for循环的话需要先将数组去重,使用map容器将元素值与元素个数存储起来,这样做就较为麻烦。我们采取第二种思路,先将数组排序 ,就以升序 为例,使用双指针法 ,指针ij分别指向数组num1num2的头部,如果两指针指向的元素相等,则输出该元素并将两指针分别后移一位;若num1[i] 大于num2[j],则指针j后移一位,i不变;若num1[i]小于num2[j],则指针i后移,j不变。

//c++代码
void jiaoji(int num1[], int num2[]){
    //假设数组num1的长度为len1,num2的长度为len2
    //先升序排序
    sort(num1, num1+len1);
    sort(num2, num2+len2);
    
    for(int i=0, j=0; i<len1 && j<len2; ){
      if(num1[i] == num2[j]){
                cout<<num1[i]<<" ";
                i++;
                j++
            }
            else if(num1[i] > num2[j]){
                j++;
            }
            else i++;
    }
}


//python代码
def jiaoji(list1, list2):
	list1.sort()
    list2.sort()
    i=j=0
    while i<len(list1) and j<len(list2):
		if list1[i] == list2[j]:
			print(list1[i], end=' ')
        elif list1[i] > list2[j]:
			j += 1
        else:
			i += 1

测试:

C++:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


void jiaoji(vector<int> num1, vector<int> num2) {

	sort(num1.begin(), num1.end());
	sort(num2.begin(), num2.end());

	for (int i = 0, j = 0; i<num1.size() && j<num2.size(); ) {
		if (num1[i] == num2[j]) {
			cout << num1[i] << " ";
			i++;
			j++;
		}

		else if (num1[i] < num2[j]) {
			i++;
		}

		else { j++; }
	}
}

int main() {
	vector<int> num1, num2;
	num1 = { 1,2,2,1,3 };
	num2 = { 2,5,9,1,2 };
	jiaoji(num1, num2);
	return 0;
}
c++.png

python:

list1 = [1,2,2,1,3]
list2 = [2,5,9,1,2]

def jiaoji(list1, list2):
	list1.sort()
	list2.sort()
	i = j = 0
	while i < len(list1) and j < len(list2):
		if list1[i] == list2[j]:
			print(list1[i], end = ' ')
			i += 1
			j += 1
		elif list1[i] > list2[j]:
			j += 1
		else:
			i += 1

jiaoji(list1, list2)

DAY Two: 最长公共前缀

题目描述:

1.png

常规思路:

先确定一个基准元素,如上图的示例1所示,我们不妨令flower为基准元素。首先创建一个指针p指向基准元素的第一个字符,通过for循环将p指向的字符与其他元素第p个字符(当p指向第一个字符时,p为0)进行比较,如果相等,则p自增,p自增后指向基准元素的第二个字符,同样与其他元素的第p个字符进行比较。当p大于基准元素长度时退出最外层循环。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

string longestCommonPrefix(vector<string>& strs) {
	if(strs.size()==0)
		return "";
	string index = strs[0], res; //res用于记录公共前缀
	int p = 0;
	if(strs.size()==1)
		return index;
	if(index.length() < 1)
		return "";
	while (p < index.length()) {
		for (int i = 1; i < strs.size(); i++) {
			if(p >= strs[i].length())
				return res;
			if (strs[i][p] != index[p]) {
				if (p == 0)
					return "";
				else
					return res;

			}

		}

		res.insert(res.end(), index[p]);  //当基准元素的第p个字符与其他元素的相等时第p的字符为公共字符,插入到res的后面
		p++;
	}
	return res;
}

这种方法运行比较耗时:

2.png

进阶思路:

首先找出前两个元素的最长公共前缀,然后找出前两个元素的最长公共前缀第三个元素 的最长公共前缀,依此类推,最后得到所有元素的最长公共前缀。

以第一个元素为基准,通过string类里的find函数来判断基准元素是否为其他元素的子串(若是find函数会返回字符串第一次出现的索引),由于我们要找的是公共前缀,若返回值为0,即可认定基准元素为其他元素的前缀。

举个例子:

flow为基准元素,string s = "flow" ,判断其与flystring v = "fly")公共前缀的方法是:

s.find(v)的值不为0,因为s里面不包含v,这时我们将s去掉最后一个字符变为flo,再判断s.find(v)的值,很显然,还是不为0,我们再去掉s的最后一个字符变为fl,再判断时,s.find(v)等于0,此时可以退出循环,并得到了flowfly的最长公共前缀为fl 。之后,将基准元素变为前两个元素的最长公共前缀,即fl,使用相同的方法判断fl与第三个元素的最长公共前缀。就这样,遍历完所有元素后得到所有元素的最长公共前缀。

#include <iostream>
#include <vector>
#include <string>
using namespace std;

string common(vector <string>& strs) {
	if (strs.size() == 0)
		return "";
	string index = strs[0];
	int length = index.length();
	if (strs.size() == 1)
		return index;
	if (length < 1)
		return "";
	for (int i = 1; i < strs.size(); i++) {
		while (strs[i].find(index) != 0) {
			length--;
			if (length == 0)
				return "";
			index = index.substr(0, length);  //去掉最后一个字符
		}
		if (strs[i].length() == 0) {
			return "";
		}
	}
	return index;
}

结果:

666.png

从两种方法的运行结果比较得知,第二种方法的效果会更好,执行时间仅有第一种方法的一半。

DAY Three:无重复字符的最长子串

题目

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
在这里插入图片描述

int lengthOfLongestSubstring(string s) {
    if(s.length()==0)
        return 0;
	int max = 1;
	int k = 0;
	int sum = 1;
	int j;
	for (int i = k + 1; i < s.length(); ) {
		for (j = k; j < i; j++) {
			if (s[i] == s[j]) 			
				break;
		}
		if (j < i) {
			++k;
			sum = 1;
			i = k + 1;
		}
		else {
			++sum;
			if (sum > max)
				max = sum;
			i++;
		}
	}
	return max;
}

DAY Four:字符串的排列

2020.08.25

题目难度 :中等
题目链接https://leetcode-cn.com/problems/permutation-in-string/
题目描述

给定两个字符串 s1s2 ,写一个函数来判断 s2 是否包含 s1 的排列。

换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例

    class Solution:
        def checkInclusion(self, s1: str, s2: str) -> bool:
            if len(s1) > len(s2):
                return False
            dic = {}
            for i in range(ord('a'),ord('z')+1):
                dic[chr(i)] = 0
            dic_s1 = {}
            for i in s1:
                dic_s1[i] = 0
            for i in s1:
                dic_s1[i] += 1
            for i in range(0,len(s1)):
                dic[s2[i]] += 1
            n = 0
            for m in range(len(s1)-1,len(s2)):
                ack = True
                if m != len(s1)-1:
                    dic[s2[m]] += 1
                    dic[s2[n]] -= 1
                    n += 1
                for i in s1:
                    if dic_s1[i] != dic[i]:
                        ack = False
                        break
                if ack:
                    return True
            return False

python

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        if(s1.length()>s2.length())
            return false;
        int dic[26] = {0};
        int dic_s1[26] = {0};
        for(int i=0;i<s1.length();i++){
            ++dic[s2[i]-'a'];
            ++dic_s1[s1[i]-'a'];
        }
        int n = 0;
        for(int i=s1.length()-1;i<s2.length();i++){
            int ack = 1;
            if(i != s1.length()-1){
                ++dic[s2[i]-'a'];
                --dic[s2[n]-'a'];
                ++n;
            }
            for(int j=0;j<s1.length();j++){
                if(dic_s1[s1[j]-'a']!=dic[s1[j]-'a']){
                    ack = 0;
                    break;
                }
            }
            if(ack)
                return true;
        }
        return false;
        
    }
};

c++
2020.08.25 下午

两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

    vector<int> twoSum(vector<int>& nums, int target) {
            unordered_map<int,int> record;
            for(int i = 0 ; i < nums.size() ; i ++){
                int complement = target - nums[i];
                if(record.find(complement) != record.end()){
                    int res[] = {record[complement],i};
                    return vector<int>(res, res + 2);
                }
                record[nums[i]] = i;
            }
            return vector<int>();
        }

三数之和

给你一个包含 n 个整数的数组 nums,判断 nums中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

    vector<vector<int>> threeSum(vector<int>& nums) {   
            vector<vector<int>> res;
            sort(nums.begin(),nums.end());
            for(int i=0; i<nums.size();i++){
                int index = nums[i];
                if(index>0)
                    break;
                int left = i + 1;
                int right = nums.size() - 1;
                if(i==0 || nums[i] != nums[i-1]){
                    while(left < right){
                        if(index + nums[left] + nums[right] < 0){
                            ++left;
                        }
                        else if(index + nums[left] + nums[right] > 0){
                            --right;
                        }
                        else{
                            int p[] = {index,nums[left], nums[right]};
                            res.push_back(vector<int>(p,p+3));
                            while(left<right && nums[left]==nums[left+1]) ++left;
                            while(left<right && nums[right]==nums[right-1]) --right;
                            ++left;
                            --right;
                        }
                    }
                }
            }
            return res;
        }

Day Five:字符串相乘

2020.08.26 星期三 多云
题目难度 :中等

题目链接https://leetcode-cn.com/problems/multiply-strings/submissions/

题目描述 :给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

说明:
num1 和 num2 的长度小于110。
num1 和 num2 只包含数字 0-9。
num1 和 num2 均不以零开头,除非是数字 0 本身。
不能使用任何标准库的大数类型(比如 BigInteger)或直接将输入转换为整数来处理。

    class Solution {
    public:
        string multiply(string num1, string num2) {
            if(num1 == "0" || num2 == "0")
                return "0";
            int m = num1.size(), n = num2.size();
            auto ans = vector<int>(m+n);   //二者相乘,结果最多有m+n位
            for(int i=m-1;i>=0;i--){
                int x = num1[i] - '0';
                for(int j = n-1;j>=0;j--){
                    int y = num2[j] - '0';
                    ans[i+j+1] += x*y;
                }
            }
            for(int i=m+n-1;i>0;i--){
                ans[i-1] += ans[i]/10;
                ans[i] %= 10;
            }
            int index = ans[0] == 0?1:0;
            string s;
            while(index<m+n){
                s.push_back(ans[index] + '0');
                ++index;
            }
            return s;
        }
    };

参考题解https://leetcode-cn.com/problems/multiply-strings/solution/zi-fu-chuan-xiang-cheng-by-leetcode-solution/

Day Six:翻转字符串里的单词

2020.08.27 星期四

题目难度 :中等

题目链接https://leetcode-cn.com/problems/reverse-words-in-a-string/

题目描述 :给定一个字符串,逐个翻转字符串中的每个单词。

在这里插入图片描述

class Solution {
public:
    string reverseWords(string s) {
        string h;
        int num = 0;
        int l = 0, r = s.length() - 1;
        while (l < r) {
            if (s[l] != ' ') {
                break;
            }
            ++l;
        }
        if (l == r) {
            if(s[r]!=' ')
            {h.push_back(s[r]);
            return h;}
            else
                return "";
        }
        while (r>l) {
            if (s[r] != ' ') {
                break;
            }
            --r;
        }
        int m_l, n_r;
        int ack = 0;
        for (int i = r; i >= l; i--) {
            if (s[i] != ' '&&ack==0) {
                ack = 1;
                num = 0;
                n_r = i;
            }	
            if (s[i] == ' ') {
                ack = 0;
                num++;
                m_l = i + 1;
            }
            if (i == l) {
                ack = 0;
                num++;
                m_l = l;
            }
            if (num == 1) {
                for (int j = m_l; j <= n_r; j++) {
                    h.push_back(s[j]);
                }
                if (m_l != l) {
                    h.push_back(' ');
                }
            }
        }
        
        return h;
    }
};

在这里插入图片描述

Day Seven:简化路径

2020.08.28 星期五

题目难度 :中等

题目描述 :以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能/ 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

在这里插入图片描述

思路简述 :使用栈的数据结构,先按照"/"将字符串分割,按照顺序依次入栈,如果遍历到..时,栈顶弹出,遇到''.时不执行任何操作

class Solution:
    def simplifyPath(self, path: str) -> str:
        path = path.split('/')
        stack = []
        for item in path:
            if item == '..':
                if stack:
                    stack.pop()
            elif item != '.' and item != '':
                stack.append(item)
            else:
                continue
        return '/' + '/'.join(stack)

在这里插入图片描述

Day Eight:岛屿的最大面积

2020.08.30 星期日

题目难度 :中等

题目描述

给定一个包含了一些 0 和 1 的非空二维数组 grid 。

一个 岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在水平或者竖直方向上相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。

找到给定的二维数组中最大的岛屿面积。(如果没有岛屿,则返回面积为 0 )

在这里插入图片描述

int num;
class Solution {
public:
    //1: no left   2: no right   3: no up   4: no down
    void sum(vector<vector<int>> &v, int x, int y, int ack){
        
       		v[x][y] = 0;
		if (ack != 1 && y - 1 >= 0) {
			if (v[x][y - 1] != 0) {
				num++;
				sum(v, x, y - 1, 2);
			}
		
		}
		if (ack != 2 && y + 1 < v[0].size()) {
			if (v[x][y + 1] != 0) {
				num++;
				sum(v, x, y + 1, 1);
			}
		
		}
	    if (ack != 3 && x - 1 >= 0) {
			if (v[x - 1][y] != 0) {
				num++;
				sum(v, x - 1, y, 4);
			}
		
		}
		if (ack != 4 && x + 1 < v.size()) {
			if (v[x + 1][y] != 0) {
				num++;
				sum(v, x + 1, y, 3);
			}
		
		}
		else
			return;
    }
    int maxAreaOfIsland(vector<vector<int>>& grid) {
        int max = 0;
        for(int x=0; x<grid.size();x++){
            for(int y=0;y<grid[0].size();y++){
                if(grid[x][y]==1){
                    num = 1;
                    sum(grid,x,y,0);
                    if(num>max)
                        max = num;
                }
            }
        }
        return max;

    }
};

在这里插入图片描述

Day Nine:钥匙和房间

2020.08.31 星期一

题目难度 :中等

题目描述 :有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,…,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。

在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j][0,1,...,N-1] 中的一个整数表示,其中 N = rooms.length。 钥匙 rooms[i][j] = v可以打开编号为 v 的房间。最初,除 0 号房间外的其余所有房间都被锁住。你可以自由地在房间之间来回走动。如果能进入每个房间返回 true,否则返回 false。

在这里插入图片描述

解法一 :深度优先搜索

class Solution {
public:
    void find(vector<vector<int>> v,vector<int> s, int *p){
        for(int i=0;i<s.size();i++){
            if(p[s[i]] > 0)
                continue;
            ++p[s[i]];
            vector<int> c;
            for(int j=0;j<v[s[i]].size();j++){
                c.push_back(v[s[i]][j]);
            }
            find(v,c,p);
        }
        return;
    }
    bool canVisitAllRooms(vector<vector<int>>& rooms) {
        int room[1000] = {0};
        room[0] = 1000;
        vector<int> s;
        for(int i=0;i<rooms[0].size();i++){
            s.push_back(rooms[0][i]);
        }
        find(rooms,s,room);
        for(int i=0;i<rooms.size();i++){
            if(room[i] == 0)
                return false;
        }
        return true;
    }
};

在这里插入图片描述

解法二 :深度优先搜索改进版

class Solution {
public:
    int num;
    vector<int> v;
    void ans(vector<vector<int>>& s, int ack){
        num++;
        v[ack] = true;
        for(auto& t:s[ack]){
            if(!v[t]){
                ans(s,t);
            }
        }
    }
    bool canVisitAllRooms(vector<vector<int>>& rooms) {
        num = 0;
        int n = rooms.size();
        v.resize(n);
        ans(rooms,0);
        return num==n;
    }
};

在这里插入图片描述

Day Ten:搜索旋转排序数组

2020.09.01 星期二

题目难度 :中等

题目描述 :假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。你可以假设数组中不存在重复的元素。

你的算法时间复杂度必须是 O(log n) 级别。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int n = (int)nums.size();
        if (!n) return -1;
        if (n == 1) return nums[0] == target ? 0 : -1;
        int l = 0, r = n - 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (nums[mid] == target) return mid;
            if (nums[0] <= nums[mid]) {
                if (nums[0] <= target && target < nums[mid]) {
                    r = mid - 1;
                } else {
                    l = mid + 1;
                }
            } else {
                if (nums[mid] < target && target <= nums[n - 1]) {
                    l = mid + 1;
                } else {
                    r = mid - 1;
                }
            }
        }
        return -1;
    }
};

Day Eleven:最长连续递增序列

2020.09.02 星期三

题目难度 :简单

题目描述 :给定一个未经排序的整数数组,找到最长且连续的的递增序列,并返回该序列的长度。

在这里插入图片描述

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        if(nums.size()==0)
            return 0;
        if(nums.size()==1)
            return 1;
        int max = 1;
        int num = 1;
        for(int i=0;i<nums.size()-1;i++){
            if(nums[i+1]>nums[i]){
                num++;
                if(num>max)
                    max = num;
            }
            else{
                num = 1;
            }
        }
        return max;
    }
};

Day Twelve:最长连续序列

2020.09.03 星期四

题目难度 :困难

题目描述 :给定一个未排序的整数数组,找出最长连续序列的长度。

​ 要求算法的时间复杂度为 O(n)

在这里插入图片描述

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.size()==0 || nums.size()==1)
            return nums.size();
        sort(nums.begin(), nums.end());
        int left = 1;
        int max = 1;
        int num = 1;
        while(left<nums.size()){
            if(nums[left] == nums[left-1] + 1){
                num++;
                if(num>max)
                    max = num;
            }
            else if(nums[left]!=nums[left-1]){
                num = 1;
                
            }
            else
                num = num;
            left++;
        }
        return max;
    }
};

在这里插入图片描述

Day Thirteen:第k个序列

2020.09.05 星期六

题目难度 :中等

题目链接 :https://leetcode-cn.com/problems/permutation-sequence/

题目描述

在这里插入图片描述

class Solution {
public:
    string getPermutation(int n, int k) {
        vector<int> factorial(n);
        factorial[0] = 1;
        for (int i = 1; i < n; ++i) {
            factorial[i] = factorial[i - 1] * i;
        }

        --k;
        string ans;
        vector<int> valid(n + 1, 1);
        for (int i = 1; i <= n; ++i) {
            int order = k / factorial[n - i] + 1;
            for (int j = 1; j <= n; ++j) {
                order -= valid[j];
                if (!order) {
                    ans += (j + '0');
                    valid[j] = 0;
                    break;
                }
            }
            k %= factorial[n - i];
        }   
        return ans; 
    }
};

在这里插入图片描述

Day Fourteen:朋友圈

2020.09.05 星期六

题目难度 :中等

题目描述 :班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。

给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
在这里插入图片描述

class Solution {
public:
    int num = 0;
    void cmp(vector<vector<int>>& v, int *a, int k){
        for(int i = 0; i<v.size(); i++){
            if(v[k][i] == 1 && k != i){
                if(a[i]==0)
                    continue;
                else{
                    a[i] = 0;
                    cmp(v, a, i);
                }
            }
        }
        
    }
    int findCircleNum(vector<vector<int>>& M) {
        int *p = new int[M.size()];
        for(int i=0; i<M.size(); i++)
            p[i] = 1;
        for(int i=0;i<M.size();i++){
            if(p[i]==1){
                if(i==0)
                    p[0]=0;
                num++;
                cmp(M,p,i);
            }
        }
        return num;
    }
};

在这里插入图片描述

Day Fifteen:避免重复字母的最小删除成本

2020.09.06 星期日

题目难度 :中等

题目描述 :给你一个字符串 s 和一个整数数组 cost ,其中 cost[i] 是从 s 中删除字符 i 的代价。

返回使字符串任意相邻两个字母不相同的最小删除成本。

请注意,删除一个字符后,删除其他字符的成本不会改变。

在这里插入图片描述

class Solution {
public:
    int minCost(string s, vector<int>& cost) {
        int i;
        for(i=0;i<s.size()-1;i++){
            if(s[i]==s[i+1])
                break;
        }
        if(i>=s.size()-1)
            return 0;
        int sum = 0;
        int l=0;
        int r=1;
        while(r<s.size()){
            if(s[l]==s[r]){
                while(s[l]==s[r])
                    r++;
                vector<int> t;
                for(int j=l;j<r;j++)
                    t.push_back(cost[j]);
                sort(t.begin(),t.end());
                for(int j=0;j<t.size()-1;j++)
                    sum += t[j];
                l = r;
                r++;
            }
            else{
                ++l;
                ++r;
            }
        }
        return sum;
    }
};

在这里插入图片描述

优化一下代码

class Solution {
public:
    int minCost(string s, vector<int>& cost) {
        int sum = 0;
        int l=0;
        int r=1;
        while(r<s.size()){
            if(s[l]==s[r]){
                while(s[l]==s[r])
                    r++;
                 int ack = 0;
        		 int max = 0;
                for(int j=l;j<r;j++){
                    if(cost[j]>max)
                        max = cost[j];
                    ack += cost[j];
                }
                sum += ack - max;
                l = r;
                r++;
            }
            else{
                ++l;
                ++r;
            }
        }
        return sum;
    }
};

在这里插入图片描述

可以看到,代码执行时间和内存占用都得到了明显的优化。

Day Sixteen:合并区间

2020.09.07 星期一

题目难度 :中等

题目描述 :给出一个区间的集合,请合并所有重叠的区间。

在这里插入图片描述

class Solution {
public:
    static bool cmp(vector<int> a, vector<int> b){
        return a[0] < b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if(intervals.size() == 1 || intervals.size() == 0)
            return intervals;
        vector<vector<int>> v;
        sort(intervals.begin(), intervals.end(), cmp);
        v.push_back(intervals[0]);
        int p = 0;
        for(int i=1;i<intervals.size();i++){
            if(intervals[i][0] <= v[p][1] && intervals[i][1] > v[p][1]){
                v[p][1] = intervals[i][1];
            }
            if(intervals[i][0] > v[p][1]){
                vector<int> s;
                s.push_back(intervals[i][0]);
                s.push_back(intervals[i][1]);
                v.push_back(s);
                p++;
            }
        }
        return v;
    }
};

在这里插入图片描述

代码优化

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.size() == 0) {
            return {};
        }
        sort(intervals.begin(), intervals.end());
        vector<vector<int>> merged;
        for (int i = 0; i < intervals.size(); ++i) {
            int L = intervals[i][0], R = intervals[i][1];
            if (!merged.size() || merged.back()[1] < L) {
                merged.push_back({L, R});
            }
            else {
                merged.back()[1] = max(merged.back()[1], R);
            }
        }
        return merged;
    }
};

在这里插入图片描述

Day Seventeen:组合

2020.09.08 星期二

题目难度 :中等

题目描述 :给定两个整数 nk,返回 1 … n 中所有可能的 k 个数的组合。

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> path;
    void backTrack(int n, int k, int index){
        if(path.size() == k){
            res.push_back(path);
            return;
        }
        for(int i = index; i <= n - (k - path.size()) + 1; i++){
            path.push_back(i);
            backTrack(n, k, i + 1);
            path.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backTrack(n, k, 1);
        return res;
    }
};

在这里插入图片描述

Day Eighteen:组合II

2020.09.10 星期四

题目难度 :中等

题目描述 :给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用一次。

说明:

所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> s;
    void backTrack(vector<int>& candidates, int target, int sum, int index, vector<bool>& used){
        if(sum > target)
            return;
        if(sum == target){
            res.push_back(s);
            return;
        }
        for(int i=index; i<candidates.size();i++){
            if( i>0 && used[i-1]==false&& candidates[i-1]==candidates[i] )
                continue;
            sum += candidates[i];
            s.push_back(candidates[i]);
            used[i] = true;
            backTrack(candidates, target, sum,i+1, used);
            used[i] = false;
            s.pop_back();
            sum -= candidates[i];
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> used(candidates.size(), false);
        sort(candidates.begin(),candidates.end());
        backTrack(candidates, target,0,0,used);
        return res;
    }
};

Day Nineteen:组合III

2020.09.11 星期五

题目难度 :正等

题目描述 :找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

  • 所有数字都是正整数。
  • 解集不能包含重复的组合。

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> res;
    vector<int> s;
    void backTrack(vector<int>& v, int ack, int k, int sum, int n, int index){
        if(ack > k)
            return;
        if(ack == k && sum != n)
            return;
        if(ack == k && sum == n){
            res.push_back(s);
            return;
        }
        for(int i = index; i < 9; i++){
            sum += v[i];
            s.push_back(v[i]);
            backTrack(v, ack + 1, k, sum, n, i+1);
            s.pop_back();
            sum -= v[i];
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        int p[] = {1,2,3,4,5,6,7,8,9};
        vector<int> jk(p, p+9);
        backTrack(jk, 0, k, 0, n, 0);
        return res;
    }
};

在这里插入图片描述

Day Twenty:三角形最小路径和

2020.09.15 星期二

题目难度 :中等

题目描述 :给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。

相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。

在这里插入图片描述

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        if(triangle.size()==0)
            return 0;
        if(triangle.size()==1)
            return triangle[0][0];
        vector<vector<int>> v(triangle.size(), vector<int>(triangle.size()));
        v[0][0] = triangle[0][0];
        for(int i=1;i<triangle.size();i++){
            for(int j=0;j<triangle[i].size();j++){
                if(j==0)
                    v[i][j] = triangle[i][j] + v[i-1][j];
                else if(j==i)
                    v[i][j] = triangle[i][j] + v[i-1][j-1];
                else{
                    v[i][j] = min(v[i-1][j], v[i-1][j-1]) + triangle[i][j];
                }
            }
        }
        int road = v[triangle.size()-1][0];
        for(int i=1;i<triangle.size();i++){
            road = min(v[triangle.size()-1][i], road);
        }
        return road;
    }
};

Day TwentyOne:分割回文串

2020.11.19 星期四 阴
题目难度 :中等
题目描述 :给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的 分割方案。
在这里插入图片描述

class Solution {
public:
    vector<vector<string>> result;
    vector<string> path;

    bool isHuiWen(string& s, int start, int end){
        for(int i = start, j = end; i < j; i++, j--){
            if(s[i] != s[j])
                return false;
        }
        return true;
    }

    void backTracing(string& s, int startIndex){
        if(startIndex >= s.size()){
            result.push_back(path);
            return;
        }
        for(int i = startIndex; i<s.size(); i++){
            if(isHuiWen(s, startIndex, i)){
                string str = s.substr(startIndex, i - startIndex + 1);
                path.push_back(str);
            }
            else{
                continue;
            }
            backTracing(s, i+1);
            path.pop_back();
        }
    }
    vector<vector<string>> partition(string s) {
        backTracing(s,0);
        return result;
    }
};

在这里插入图片描述

Day Twenty One:三角形周长

2020.11.29 星期日 晴

题目描述

21题

题解

给出两种解题思路,一种是回溯法,一种是贪心。

  • 回溯法

简单地说就是遍历所有可能的组合情况,可以用一个向量vector<int> shu 来存储三边的长度,使用标记符b 来判断是否集齐三边。b 初始值为0,shu 里每添加一个元素b 的值就加1,当b 的值为3时,集齐了三边,然后判断任意两边长度是否大于第三边,如果符合三角形的定义,就计算周长并赋值给res (这里res 只记录最大的周长值)。遍历完所有情况后res 里的值就是最大周长值。

缺点:时间复杂度太大

//回溯法
class Solution {
public:
    int res = 0;
    vector<int> shu;
    int b = 0;
    void back(vector<int>& A, int index) {
        if (b == 3) {
            if (shu[0] + shu[1] > shu[2] && shu[0] + shu[2] > shu[1] && shu[1] + shu[2] > shu[0]) {
                int sum = shu[0] + shu[1] + shu[2];
                if (sum > res) res = sum;
            }
            return;
        }
        for (int i = index; i < A.size(); i++) {
            shu.push_back(A[i]);
            b++;
            back(A, i + 1);
            b--;
            shu.pop_back();
        }

    }
    int largestPerimeter(vector<int>& A) {
        back(A, 0);
        return res;
    }
};
  • 贪心

首先对原数组进行排序,因为要找最大的周长,故从大向小找起,然后判断最小的的两边长度之和是否大于第三边,如果符合条件,则找到最优解,否则换另一个最大边进行判断。

//贪心
class Solution {
public:
    int largestPerimeter(vector<int>& A) {
        sort(A.begin(), A.end());
        for (int i = A.size() -1; i >= 2; i--) {
            if (A[i - 1] + A[i - 2] > A[i])
                return A[i] + A[i - 1] + A[i - 2];
        }
        return 0;
    }
};

时间

每日更新!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值