第二周作业(3.2)

时间:2021-02-24 22:00:52

第二周作业

目录:

  • 本周完成题目
  • 主要过程思路
  • 相关代码
  • 感想与总结

一、本周完成题目

本周共完成3道题目,其中1道Easy,1道Medium,1道Hard。针对于本周所学的知识选择了类似的Divide and Conquer Tag下的题目。 Divide and Conquer

具体完成题目及难度如下表:

# Title Difficulty
169 Majority Element Easy
215 Kth Largest Element in an Array Medium
312 Burst Balloons Hard

题目内容

1、Majority Element 
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
找到数组中出现次数大于 ⌊ n/2 ⌋ 的数字。

2、Kth Largest Element in an Array
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
找到数组中第k大的数字。

3、Burst Balloons
Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
有n个气球,每次扎破一个球,总数上会加上这个球和相邻左右两个气球的数字乘积。求全部气球扎破后最大的总数。

Example:

Given [3, 1, 5, 8]

Return 167

   nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167

二、主要过程思路

Majority Element

首先需要明确的是超过二分之一出现的数字有且仅有一个,也就是说,可以对于数组进行遍历,只要一个数字出现的次数超过二分之一则可以直接输出该数字为结果。
具体而言,为了便于计数,使用了map结构,以数字作为index,对于数组进行遍历。每出现一次对应数字出现次数加一同时进行判断次数是否大于总数的二分之一,直到找到所需的结果。

Kth Largest Element in an Array

这一题我直接使用了sort函数对于整个数组进行排序后返回第k大的值。
注:sort函数使用的是经过调优的快速排序法。

Burst Balloons

本题开始时我的思路是,假设共有n个气球,那么扎破这个气球之后仍剩余n-1个气球,去掉扎破的气球又形成了新的类似问题。依次类推共有n!种情况,找到里面最小的值。但是很明显这样的时间复杂度比较高,为O(n!)

之后参考了Solution中的一个算法进行了理解:https://discuss.leetcode.com/topic/41086/c-dp-detailed-explanation
方法的主要思路是从最短区间开始,判断不同长度区间扎破气球的计算最大值。

具体来说,根据提示首先在数组前后个添加一个1,则现在的编号为0到n+1。设定l和r分别代表区间的左右两端,len代表区间的长度,设定一个二维数组dp[l][r]用于保存l与r之间区间扎破气球后的最大和(不包括边界)。
len从2开始到n+1,l从0开始一直到n+1-len,r=l+len。对于区间内的每个数字进行遍历,假设最后剩下的是第i个数字,那么最后的数字一定为nums[l]*nums[i]*nums[r]。
相当于将区间切为了2半:
第二周作业(3.2)
白色部分的所有点在最后一步之前都已经被扎破,且左右两边不会有影响,这两部分的总和即为dp[l][i]+dp[i][r]。
也就是说,在该区间上,若最后被扎破的是第i个数字,则总和为:
nums[l]*nums[i]*nums[r]+dp[l][i]+dp[i][r]
对于每个区间只需要保存总和最大的值作为之后更大区间的子区间。
最后只需要返回dp[0][n+1],即为最后的结果。

以[3,1,5,8]为例,dp变化情况如下:
len=2时,dp如下:

0    3    0    0    0    0
0 0 15 0 0 0
0 0 0 40 0 0
0 0 0 0 40 0
0 0 0 0 0 0

len=3时,dp如下:

0    3    30   0    0    0
0 0 15 135 0 0
0 0 0 40 48 0
0 0 0 0 40 0
0 0 0 0 0 0

len=4时:

0    3    30   159  0    0
0 0 15 135 159 0
0 0 0 40 48 0
0 0 0 0 40 0
0 0 0 0 0 0

len=5时:

0    3    30   159  167  0
0 0 15 135 159 0
0 0 0 40 48 0
0 0 0 0 40 0
0 0 0 0 0 0

最后结果即为dp[0][5]=167。
总体而言时间复杂度为O(n^3),大大降低。

三、相关代码

Majority Element

class Solution {
public:
int majorityElement(vector<int>& nums) {
map<int,int> numOfexist;
int n=nums.size();
for(int i=0;i<n;i++){
numOfexist[nums[i]]++;
if(numOfexist[nums[i]]>n/2){
return nums[i];
}
}
}
};

Kth Largest Element in an Array

class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int l=nums.size()-k;
return nums[l];
}
};

Burst Balloons

class Solution {
public:
int maxCoins(vector<int>& nums) {
int n = nums.size();
//增加nums[-1] = nums[n] = 1
nums.insert(nums.begin(), 1);
nums.insert(nums.end(), 1);
//int dp[500][502]={0};
vector<vector<int>> dp(nums.size(), vector<int>(nums.size(), 0));
int l,r;
for(int len=2;len<=n+1;len++){
for(l=0;l<=n+1-len;l++){
r=l+len;
for(int i=l+1;i<r;i++){
dp[l][r]=max(dp[l][r],nums[l]*nums[r]*nums[i]+dp[l][i]+dp[i][r]);
}
}
}
return dp[0][n+1];
}
};

四、感想与总结

本周主要涉及到Divide and Conquer(分治法)的一些思路,相对上周来说难度有一定提升。代码其实非常简单,但是需要找到合适的方法对于问题进行分解与递归,在这一步上比较难想到合适的方法。
本周的第三题借鉴了他人的思路,不过也花了一些时间进行理解。对于分治法有了一定新理解。