给定一个数组 = {1 2 3 3 2 4 6 7}
最长递增子数组是 2 4 6 7。需要注意的是,这与最长递增子序列并不相同,因为值必须是连续的。
是否有 O(n) 的解决方案?
def DP(a[]):
dp[1] = 1
for i = 2 to n:
if a[i] > a[i - 1]:
dp[i] = dp[i - 1] + 1
else:
dp[i] = 1
1 < 2 < 3 >= 3 >= 2 < 4 < 6 < 7
| 1 2 3 | 1 | 1 2 3 4 <- Length of runs
1 < 2 < 3 >= 3 >= 2 < 4 < 6 < 7
| 1 2 3 | 1 | 1 2
^
Longest run,
ending at index 2
1 < 2 < 3 >= 3 >= 2 < 4 < 6 < 7
| 1 2 3 | 1 | 1 2 3 4
^ ^
Longest run, Current run ends
ending at index 2 Better than last longest run, update
由于您只遍历一次数组,每次仅访问一个元素和最佳运行数据,因此每个元素的时间是恒定的。因此,该算法的运行时间为O(n)
。
是的,你可以用o(n)的时间复杂度找到最长的子数组。从开头开始,记录当前序列和最长的序列。每一步,如果元素比前一个大,则增加当前序列的长度。如果当前序列比最长序列长,则更新最长序列。如果当前元素比前一个小,则重置计数器。最后你会得到最长的序列。
int flag = 0;
int maxSubarray =0;
int maxStart=0,maxEnd=0,start=0,end=0;
for(int i=1;i<n;i++){
if(a[i-1]<a[i]){
if(flag!=1){
start = i-1;
flag=1;
}
if(i == n-1){
end = n-1;
}
}
else{
if(flag==1 ){
end = i-1;
flag =0;
}
}
if(maxSubarray < end - start){
maxSubarray = end - start;
maxStart = start;
maxEnd = end;
}
}
System.out.println(maxSubarray);
System.out.println("Starting index = "+maxStart+" Ending index = "+maxEnd);`
Jun HU的回答是正确的,但我认为我们不需要维护一个占用O(n)空间的数组。相反,我们可以跟踪当前子数组的大小,类似于
int maxSize, currentSize = 1;
for (int i = 1; i < array.size(); i++) {
if (array[i] > array[i-1]) {
currentSize++;
maxSize = max(currentSize, maxSize);
} else {
currentSize = 1;
}
}
这不是动态规划的解决方案,但我尝试了一些场景,看起来可以正常工作。也许对你来说是一个很好的起点。
public static int MaxSlice(int[] A)
{
//100,40,45,50,55,60, 30,20,40,25,28,30
int maxstartIndex = 0;
int MaxAscendingCount = 0;
int thisStartIndex = 0;
int thisAscendingCount = 0;
bool reset = false;
bool wasLastAscending = false;
for (int i = 0; i < A.Length-1; i++ )
{
if (A[i + 1] > A[i])
{
if(!wasLastAscending)
thisStartIndex = i;
thisAscendingCount++;
wasLastAscending = true;
}
else
{
reset = true;
wasLastAscending = false;
}
if (reset && thisAscendingCount > MaxAscendingCount)
{
MaxAscendingCount = thisAscendingCount;
maxstartIndex = thisStartIndex;
reset = false;
thisAscendingCount = 0;
}
}
MaxAscendingCount = thisAscendingCount;
maxstartIndex = thisStartIndex;
return maxstartIndex;
}
public static Range getLargest(int[] array) {
int max = 1;
int start = 0;
int aux = 0;
int count = 1;
for (int i = 1; i < array.length; i++) {
if (array[i] > array[i - 1]) {
count++;
} else {
aux = i;
count = 1;
}
if (count > max) {
max = count;
start = aux;
}
}
return new Range(start, start + max - 1);
}
public static class Range {
public final int start;
public final int end;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
}
import java.util.Arrays;
public class LongestIncreasing {
private static class PairHolder<T> {
int start = -1;
int end = -1;
int weight = -1;
PairHolder(int start, int end) {
this.start = start;
this.end = end;
this.weight = start == -1 ? -1 : end-start+1;
}
String getSubArray(T[] arr) {
return Arrays.toString(Arrays.copyOfRange(arr, start, end+1));
}
@Override
public String toString() {
return "[" + start + ", " + end + ", weight: " + weight + "]";
}
}
public static <T extends Comparable<? super T>> void getContiguousChain(T[] chain) {
int start = -1, end = -1;
PairHolder<T> longest = new PairHolder<T>(-1, -1);
for (int i = 0; i < chain.length - 1; i++) {
if (start == -1) {
start = i;
end = i;
}
if (chain[i+1].compareTo(chain[i]) == -1 || chain[i+1].compareTo(chain[i]) == 0) {
if (end-start+1 > longest.weight) {
longest = new PairHolder<T>(start, end);
}
start = -1; end = -1;
continue;
}
end = i+1;
}
if (end-start+1 > longest.weight) { //corner case where last element of chain is also end of array
longest = new PairHolder<T>(start, end);
}
System.out.println(longest.getSubArray(chain));
}
public static void main(String[] args) {
Integer[] arr = {2, 3, 3, 4, 5, 6, 2, 9, 10, 12, 14, 13};
getContiguousChain(arr);
}
}
def lis(a):
m = 0
c = 1
index = 0
for i in xrange(1, len(a)):
x = a[i]
if x > a[i - 1]:
c += 1
else:
if c > m:
m = c
index = i
c = 1
if c > m:
m = c
index = i
return a[i - m + 1: i + 1]