你將會獲得一系列視頻片段,這些片段來自於一項持續時長爲 T 秒的體育賽事。這些片段可能有所重疊,也可能長度不一。
視頻片段 clips[i] 都用區間進行表示:開始於 clips[i][0] 並於 clips[i][1] 結束。我們甚至可以對這些片段自由地再剪輯,例如片段 [0, 7] 可以剪切成 [0, 1] + [1, 3] + [3, 7] 三部分。
我們需要將這些片段進行再剪輯,並將剪輯後的內容拼接成覆蓋整個運動過程的片段([0, T])。返回所需片段的最小數目,如果無法完成該任務,則返回 -1
Input: clips = [[0,2],[4,6],[8,10],[1,9],[1,5],[5,9]], T = 10 Output: 3 Explanation: We take the clips [0,2], [8,10], [1,9]; a total of 3 clips. Then, we can reconstruct the sporting event as follows: We cut [1,9] into segments [1,2] + [2,8] + [8,9]. Now we have segments [0,2] + [2,8] + [8,10] which cover the sporting event [0, 10].
思路:
給了一堆區間,要求選取最少的區間,這些區間能覆蓋[0, T]區間。要想最少區間,就要每個區間儘可能大,覆蓋的範圍廣。
//直觀想法,從起點0開始,獲取到最長的片段終點,然後再用得到的額終點作爲起點,在來獲取新的片段終點,直到T爲止
public int videoStitching(int[][] clips, int T) {
int res = 0;
int e = 0;
while (e < T) {
int tmp = e;
e = getLongest(e, clips);
if (tmp == e) return -1;
++res;
}
return res;
}
// 獲取最長片段,輸入起點,輸出終點
private int getLongest(int s, int[][] clips) {
int max = 0;
for (int[] c : clips) {
if (c[0] <= s && c[1] >= s) max = Math.max(max, c[1]);
}
return max;
}
和jump game II類似
利用貪心算法,先對數組排序,先按開始數值從小到大排序,若兩者相等,在按照結束節點排序。
用一個curend表示每一選中的最大片段範圍的結束點數值,當遍歷到clips[i][0]>curend,表示從i開始不能被之前的curend覆蓋,所以需要選中一個新的區間,然後更新curend爲最新得到的最大值。
public int videoStitching0(int[][] clips, int T) {
int len=clips.length;
Arrays.sort(clips, new Comparator<int[]>() {
@Override
public int compare(int[] c1, int[] c2) {
if (c1[0] != c2[0]) {
return c1[0] - c2[0];
}
return c2[1] - c1[1];
}
});
if(clips[0][0]>0)return -1;
int res=0;
int curend=0;//代表被選中的範圍的首尾
for(int i=0;i<len;){
if(clips[i][0] > curend) {//有間隔,無法保證0--T被覆蓋
return -1;
}
int tempend=curend;
while(i<len&&clips[i][0]<=curend){//表示遍歷的第i個片段的起點在選取的end前面,所以要通過比較得出更大的end數值
tempend=Math.max(tempend,clips[i][1]);
i++;
}
res++;//最新的i位置的開始數值不在end前面,所以需要加1,需要在來一個區間
if(tempend>=T){
return res;
}
curend=tempend;
}
return -1;
}
不使用排序,更快一點,先用一個數組 end[T],下標代表的是其實節點,數組的數值代表以下標作爲起始節點的片段的最大結束節點,然後再用循環來如何最少拼接。從0開始,開始爲上個的結束的值+1,新的結束點爲之前得到的end數組中的最大的結束的值
public int videoStitching2(int[][] clips, int T) {
int len=clips.length;
if(len==0)return -1;
int end[]=new int[T];
for(int t[]:clips){
if(t[0]>=T)continue;
end[t[0]]=Math.max(t[1],end[t[0]]);
}
int l=0,r=0,last=0,res=0;
while(true){
for(int i=l;i<=r;i++){
last=Math.max(last,end[i]);
}
if(last<=r)return -1;//相當於有斷裂,clips[i][0]>curend
res++;
if(last>=T)return res;
l=r+1;
r=last;
}
}
動態規劃,最慢
//動態規劃
public int videoStitching3(int[][] clips, int T) {
int[][] dp= new int[T+1][T+1];
for(int i=0; i<=T; i++){
for(int j=0; j<=T; j++){
dp[i][j]=101;
}
}
for(int[] clip : clips){
int s=clip[0];
int r=clip[1];
for(int len=1; len<=T; len++){
for(int start=0; start<=T-len; start++){
int right= start+len;
if(s>right || r<start){continue;}
if(s<=start && r>=right){dp[start][right]=1;}
else if(s<=start){dp[start][right]= Math.min(dp[start][right], dp[r][right]+1);}
else if( r>=right){dp[start][right]= Math.min(dp[start][right], dp[start][s]+1);}
else if(s>start && r<right){dp[start][right]= Math.min(dp[start][right], dp[start][s]+1+dp[r][right]);}
}
}
}
return( dp[0][T]==101 ? -1 :dp[0][T]) ;
}