Dinamik programlama kullanarak en uzun artan alt sekans nasıl belirlenir?


Yanıtlar:


404

Tamam, önce O (N ^ 2) olan en basit çözümü açıklayacağım, burada N koleksiyonun boyutu. Ayrıca açıklayacağım bir O (N log N) çözümü de var. Bakın burada bölüm Verimli algoritmalar de bunun için.

Dizinin indeksleri 0 - N - 1 arasında olduğunu varsayacağım. Öyleyse DP[i]indeksli elemanda biten LIS (En uzun artan alt sekans) uzunluğu olarak tanımlayalım i. Hesaplamak için DP[i]hepimiz endekslerin bakmak j < ive eğer hem kontrol DP[j] + 1 > DP[i]ve array[j] < array[i](biz artan olmak istiyorum). Bu doğruysa, mevcut optimum değerini güncelleyebiliriz DP[i]. Dizi için global optimum değeri bulmak için maksimum değeri alabilirsiniz DP[0...N - 1].

int maxLength = 1, bestEnd = 0;
DP[0] = 1;
prev[0] = -1;

for (int i = 1; i < N; i++)
{
   DP[i] = 1;
   prev[i] = -1;

   for (int j = i - 1; j >= 0; j--)
      if (DP[j] + 1 > DP[i] && array[j] < array[i])
      {
         DP[i] = DP[j] + 1;
         prev[i] = j;
      }

   if (DP[i] > maxLength)
   {
      bestEnd = i;
      maxLength = DP[i];
   }
}

Diziyi prevdaha sonra sadece uzunluğunu değil gerçek diziyi bulmak için kullanabilirsiniz. Sadece bestEndkullanarak bir döngü içinde özyinelemeli geri gidin prev[bestEnd]. -1Değer durdurmak için bir işarettir.


Tamam, şimdi daha verimli O(N log N)çözüme:

Izin vermek S[pos]artan uzunluk dizisi sona eren en küçük tamsayı olarak tanımlanacaktır pos. Şimdi Xgiriş kümesinin her tamsayısını tekrarlayın ve aşağıdakileri yapın:

  1. X> SÖğesindeki son öğe varsa X, sonuna sonuna ekleyin S. Bu aslında yeni bir en büyük bulduğumuz anlamına geliyor LIS.

  2. Aksi takdirde en küçük elemanı bulmak Solduğunu, >=daha X, ve bunu değiştirmek X. Çünkü Sher an sıralanır, eleman ikili arama özelliğini kullanarak bulunabilir log(N).

Toplam çalışma zamanı - Ntamsayılar ve her biri için ikili arama - N * günlüğü (N) = O (N günlüğü N)

Şimdi gerçek bir örnek yapalım:

Tamsayıların toplanması: 2 6 3 4 1 2 9 5 8

Adımlar:

0. S = {} - Initialize S to the empty set
1. S = {2} - New largest LIS
2. S = {2, 6} - New largest LIS
3. S = {2, 3} - Changed 6 to 3
4. S = {2, 3, 4} - New largest LIS
5. S = {1, 3, 4} - Changed 2 to 1
6. S = {1, 2, 4} - Changed 3 to 2
7. S = {1, 2, 4, 9} - New largest LIS
8. S = {1, 2, 4, 5} - Changed 9 to 5
9. S = {1, 2, 4, 5, 8} - New largest LIS

Yani LIS'in uzunluğu 5(S'nin büyüklüğü).

Gerçek olanı yeniden yapılandırmak için LIStekrar bir üst dizi kullanacağız. Izin vermek parent[i]endeks iile LISbiten endeks ile eleman selefi olsun i.

İşleri daha basit hale getirmek için S, gerçek tamsayıları değil, kümedeki indekslerini (konumları) dizide tutabiliriz . Biz tutmayız {1, 2, 4, 5, 8}, tutuyoruz {4, 5, 3, 7, 8}.

Bu giriş [4] = 1 , giriş [5] = 2 , giriş [3] = 4 , giriş [7] = 5 , giriş [8] = 8 .

Üst diziyi düzgün şekilde güncellersek, gerçek LIS:

input[S[lastElementOfS]], 
input[parent[S[lastElementOfS]]],
input[parent[parent[S[lastElementOfS]]]],
........................................

Şimdi önemli olan şey - ana diziyi nasıl güncelleyebiliriz? İki seçenek vardır:

  1. X> Öğesindeki son öğe varsa S, o zaman parent[indexX] = indexLastElement. Bu, en yeni öğenin üst öğesinin son öğe olduğu anlamına gelir. Biz sadece Xsonuna kadar başlıyoruz S.

  2. Aksi takdirde en küçük elemanın indeksini bulmak Solduğunu >=daha Xve bunu değiştirmek X. İşte parent[indexX] = S[index - 1].


4
Önemli değil. Eğer DP[j] + 1 == DP[i]o DP[i]zaman daha iyi olmaz DP[i] = DP[j] + 1. Optimize etmeye çalışıyoruz DP[i].
Petar Minchev

11
Ama burada cevap şu olmalı [1,2,5,8], 4 dizide 1'den önce geliyor, LIS nasıl olabilir [1,2,4,5,8]?
SexyBeast

19
@Cupidvogel - Cevap [2,3,4,5,8]. Dikkatle okuyun - Sdizi DOES NOTgerçek bir diziyi temsil eder. Let S[pos] be defined as the smallest integer that ends an increasing sequence of length pos.
Petar Minchev

8
Sık sık bu tür net açıklamalar görmüyorum. Sadece anlaşılması çok kolay değildir, çünkü şüpheler açıklama içinde giderilir, aynı zamanda ortaya çıkabilecek herhangi bir uygulama sorununu da giderir. Muhteşem.
Boyang

16
geeksforgeeks.org/… muhtemelen bunun gördüğüm en iyi açıklaması
eb80

57

Petar Minchev'in açıklaması benim için her şeyin netleşmesine yardımcı oldu, ama her şeyin ne olduğunu ayrıştırmak benim için zor oldu, bu yüzden aşırı tanımlayıcı değişken isimleri ve çok sayıda yorum içeren bir Python uygulaması yaptım. Bir saf özyinelemeli çözüm, O (n ^ 2) çözüm ve O (n log n) çözüm yaptım.

Umarım algoritmaları temizlemeye yardımcı olur!

Özyinelemeli Çözüm

def recursive_solution(remaining_sequence, bigger_than=None):
    """Finds the longest increasing subsequence of remaining_sequence that is      
    bigger than bigger_than and returns it.  This solution is O(2^n)."""

    # Base case: nothing is remaining.                                             
    if len(remaining_sequence) == 0:
        return remaining_sequence

    # Recursive case 1: exclude the current element and process the remaining.     
    best_sequence = recursive_solution(remaining_sequence[1:], bigger_than)

    # Recursive case 2: include the current element if it's big enough.            
    first = remaining_sequence[0]

    if (first > bigger_than) or (bigger_than is None):

        sequence_with = [first] + recursive_solution(remaining_sequence[1:], first)

        # Choose whichever of case 1 and case 2 were longer.                         
        if len(sequence_with) >= len(best_sequence):
            best_sequence = sequence_with

    return best_sequence                                                        

O (n ^ 2) Dinamik Programlama Çözümü

def dynamic_programming_solution(sequence):
    """Finds the longest increasing subsequence in sequence using dynamic          
    programming.  This solution is O(n^2)."""

    longest_subsequence_ending_with = []
    backreference_for_subsequence_ending_with = []
    current_best_end = 0

    for curr_elem in range(len(sequence)):
        # It's always possible to have a subsequence of length 1.                    
        longest_subsequence_ending_with.append(1)

        # If a subsequence is length 1, it doesn't have a backreference.             
        backreference_for_subsequence_ending_with.append(None)

        for prev_elem in range(curr_elem):
            subsequence_length_through_prev = (longest_subsequence_ending_with[prev_elem] + 1)

            # If the prev_elem is smaller than the current elem (so it's increasing)   
            # And if the longest subsequence from prev_elem would yield a better       
            # subsequence for curr_elem.                                               
            if ((sequence[prev_elem] < sequence[curr_elem]) and
                    (subsequence_length_through_prev >
                         longest_subsequence_ending_with[curr_elem])):

                # Set the candidate best subsequence at curr_elem to go through prev.    
                longest_subsequence_ending_with[curr_elem] = (subsequence_length_through_prev)
                backreference_for_subsequence_ending_with[curr_elem] = prev_elem
                # If the new end is the best, update the best.    

        if (longest_subsequence_ending_with[curr_elem] >
                longest_subsequence_ending_with[current_best_end]):
            current_best_end = curr_elem
            # Output the overall best by following the backreferences.  

    best_subsequence = []
    current_backreference = current_best_end

    while current_backreference is not None:
        best_subsequence.append(sequence[current_backreference])
        current_backreference = (backreference_for_subsequence_ending_with[current_backreference])

    best_subsequence.reverse()

    return best_subsequence                                                   

O (n log n) Dinamik Programlama Çözümü

def find_smallest_elem_as_big_as(sequence, subsequence, elem):
    """Returns the index of the smallest element in subsequence as big as          
    sequence[elem].  sequence[elem] must not be larger than every element in       
    subsequence.  The elements in subsequence are indices in sequence.  Uses       
    binary search."""

    low = 0
    high = len(subsequence) - 1

    while high > low:
        mid = (high + low) / 2
        # If the current element is not as big as elem, throw out the low half of    
        # sequence.                                                                  
        if sequence[subsequence[mid]] < sequence[elem]:
            low = mid + 1
            # If the current element is as big as elem, throw out everything bigger, but 
        # keep the current element.                                                  
        else:
            high = mid

    return high


def optimized_dynamic_programming_solution(sequence):
    """Finds the longest increasing subsequence in sequence using dynamic          
    programming and binary search (per                                             
    http://en.wikipedia.org/wiki/Longest_increasing_subsequence).  This solution   
    is O(n log n)."""

    # Both of these lists hold the indices of elements in sequence and not the        
    # elements themselves.                                                         
    # This list will always be sorted.                                             
    smallest_end_to_subsequence_of_length = []

    # This array goes along with sequence (not                                     
    # smallest_end_to_subsequence_of_length).  Following the corresponding element 
    # in this array repeatedly will generate the desired subsequence.              
    parent = [None for _ in sequence]

    for elem in range(len(sequence)):
        # We're iterating through sequence in order, so if elem is bigger than the   
        # end of longest current subsequence, we have a new longest increasing          
        # subsequence.                                                               
        if (len(smallest_end_to_subsequence_of_length) == 0 or
                    sequence[elem] > sequence[smallest_end_to_subsequence_of_length[-1]]):
            # If we are adding the first element, it has no parent.  Otherwise, we        
            # need to update the parent to be the previous biggest element.            
            if len(smallest_end_to_subsequence_of_length) > 0:
                parent[elem] = smallest_end_to_subsequence_of_length[-1]
            smallest_end_to_subsequence_of_length.append(elem)
        else:
            # If we can't make a longer subsequence, we might be able to make a        
            # subsequence of equal size to one of our earlier subsequences with a         
            # smaller ending number (which makes it easier to find a later number that 
            # is increasing).                                                          
            # Thus, we look for the smallest element in                                
            # smallest_end_to_subsequence_of_length that is at least as big as elem       
            # and replace it with elem.                                                
            # This preserves correctness because if there is a subsequence of length n 
            # that ends with a number smaller than elem, we could add elem on to the   
            # end of that subsequence to get a subsequence of length n+1.              
            location_to_replace = find_smallest_elem_as_big_as(sequence, smallest_end_to_subsequence_of_length, elem)
            smallest_end_to_subsequence_of_length[location_to_replace] = elem
            # If we're replacing the first element, we don't need to update its parent 
            # because a subsequence of length 1 has no parent.  Otherwise, its parent  
            # is the subsequence one shorter, which we just added onto.                
            if location_to_replace != 0:
                parent[elem] = (smallest_end_to_subsequence_of_length[location_to_replace - 1])

    # Generate the longest increasing subsequence by backtracking through parent.  
    curr_parent = smallest_end_to_subsequence_of_length[-1]
    longest_increasing_subsequence = []

    while curr_parent is not None:
        longest_increasing_subsequence.append(sequence[curr_parent])
        curr_parent = parent[curr_parent]

    longest_increasing_subsequence.reverse()

    return longest_increasing_subsequence         

19
Buradaki çabayı takdir etsem de, bu sahte kodlara baktığımda gözlerim acıyor.
mostruash

94
mostruash - Ne demek istediğinden emin değilim. Cevabımın sahte kodu yok; Python'u var.
Sam King

10
Muhtemelen büyük olasılıkla gözlerimi '
incittirdi

19
Adlandırma kuralımı kastediyorsanız, çoğunlukla Google Python Stil Kılavuzu'nu izliyorum. Kısa değişken adlarını savunuyorsanız, açıklayıcı değişken adlarını tercih ediyorum çünkü kodun anlaşılmasını ve bakımını kolaylaştırıyorlar.
Sam King

10
Gerçek bir uygulama için, muhtemelen kullanılması mantıklı olacaktır bisect. Bir algoritmanın nasıl çalıştığının ve performans özelliklerinin bir gösterimi için, işleri mümkün olduğunca ilkel tutmaya çalışıyordum.
Sam King

22

DP çözümü hakkında konuşan ben kimsenin LIS indirgenebilir gerçeğini bahsettiği şaşırtıcı bulundu LCS . Tek yapmanız gereken orijinal dizinin kopyasını sıralamak, tüm kopyaları kaldırmak ve LCS yapmaktır. Sözde kodda:

def LIS(S):
    T = sort(S)
    T = removeDuplicates(T)
    return LCS(S, T)

Ve Go'da yazılmış tam uygulama. Çözümü yeniden yapılandırmanız gerekmiyorsa, n ^ 2 DP matrisinin tamamını korumanıza gerek yoktur.

func lcs(arr1 []int) int {
    arr2 := make([]int, len(arr1))
    for i, v := range arr1 {
        arr2[i] = v
    }
    sort.Ints(arr1)
    arr3 := []int{}
    prev := arr1[0] - 1
    for _, v := range arr1 {
        if v != prev {
            prev = v
            arr3 = append(arr3, v)
        }
    }

    n1, n2 := len(arr1), len(arr3)

    M := make([][]int, n2 + 1)
    e := make([]int, (n1 + 1) * (n2 + 1))
    for i := range M {
        M[i] = e[i * (n1 + 1):(i + 1) * (n1 + 1)]
    }

    for i := 1; i <= n2; i++ {
        for j := 1; j <= n1; j++ {
            if arr2[j - 1] == arr3[i - 1] {
                M[i][j] = M[i - 1][j - 1] + 1
            } else if M[i - 1][j] > M[i][j - 1] {
                M[i][j] = M[i - 1][j]
            } else {
                M[i][j] = M[i][j - 1]
            }
        }
    }

    return M[n2][n1]
}

@max evet, LCS, n ^ 2 matrisi ile cevapta bir çeşit yazılmıştır
Salvador Dali

10

Aşağıdaki C ++ uygulaması, aynı zamanda, adlandırılan bir dizi kullanarak gerçek en uzun artan alt dizeyi oluşturan bazı kodları içerir prev.

std::vector<int> longest_increasing_subsequence (const std::vector<int>& s)
{
    int best_end = 0;
    int sz = s.size();

    if (!sz)
        return std::vector<int>();

    std::vector<int> prev(sz,-1);
    std::vector<int> memo(sz, 0);

    int max_length = std::numeric_limits<int>::min();

    memo[0] = 1;

    for ( auto i = 1; i < sz; ++i)
    {
        for ( auto j = 0; j < i; ++j)
        {
            if ( s[j] < s[i] && memo[i] < memo[j] + 1 )
            {
                memo[i] =  memo[j] + 1;
                prev[i] =  j;
            }
        }

        if ( memo[i] > max_length ) 
        {
            best_end = i;
            max_length = memo[i];
        }
    }

    // Code that builds the longest increasing subsequence using "prev"
    std::vector<int> results;
    results.reserve(sz);

    std::stack<int> stk;
    int current = best_end;

    while (current != -1)
    {
        stk.push(s[current]);
        current = prev[current];
    }

    while (!stk.empty())
    {
        results.push_back(stk.top());
        stk.pop();
    }

    return results;
}

Yığını olmayan uygulama sadece vektörü tersine çevirir

#include <iostream>
#include <vector>
#include <limits>
std::vector<int> LIS( const std::vector<int> &v ) {
  auto sz = v.size();
  if(!sz)
    return v;
  std::vector<int> memo(sz, 0);
  std::vector<int> prev(sz, -1);
  memo[0] = 1;
  int best_end = 0;
  int max_length = std::numeric_limits<int>::min();
  for (auto i = 1; i < sz; ++i) {
    for ( auto j = 0; j < i ; ++j) {
      if (s[j] < s[i] && memo[i] < memo[j] + 1) {
        memo[i] = memo[j] + 1;
        prev[i] = j;
      }
    }
    if(memo[i] > max_length) {
      best_end = i;
      max_length = memo[i];
    }
  }

  // create results
  std::vector<int> results;
  results.reserve(v.size());
  auto current = best_end;
  while (current != -1) {
    results.push_back(s[current]);
    current = prev[current];
  }
  std::reverse(results.begin(), results.end());
  return results;
}

4

Sorunu dinamik programlama açısından değerlendirmenin üç adımı:

  1. Yineleme tanımı: maxLength (i) == 1 + maxLength (j) burada 0 <j <i ve dizi [i]> dizi [j]
  2. Yineleme parametresi sınırı: 0 ile i - 1 alt sekansları bir parametre olarak geçirilebilir
  3. Değerlendirme sırası: alt sekansı arttırdığı için, 0'dan n'ye kadar değerlendirilmesi gerekir

{0, 8, 2, 3, 7, 9} dizinini örnek olarak alırsak:

  • [0] temel dava olarak {0} alt dizisini alacağız
  • [1] 1 yeni alt dizimiz var {0, 8}
  • [2] iki alt diziyi {0, 8, 2} ve {0, 2}, mevcut alt dizilere dizin 2'ye eleman ekleyerek değerlendirmeye çalışın - yalnızca bir tanesi geçerlidir, bu nedenle yalnızca üçüncü olası {0, 2} dizisini ekleyerek parametre listesine ...

İşte çalışan C ++ 11 kodu:

#include <iostream>
#include <vector>

int getLongestIncSub(const std::vector<int> &sequence, size_t index, std::vector<std::vector<int>> &sub) {
    if(index == 0) {
        sub.push_back(std::vector<int>{sequence[0]});
        return 1;
    }

    size_t longestSubSeq = getLongestIncSub(sequence, index - 1, sub);
    std::vector<std::vector<int>> tmpSubSeq;
    for(std::vector<int> &subSeq : sub) {
        if(subSeq[subSeq.size() - 1] < sequence[index]) {
            std::vector<int> newSeq(subSeq);
            newSeq.push_back(sequence[index]);
            longestSubSeq = std::max(longestSubSeq, newSeq.size());
            tmpSubSeq.push_back(newSeq);
        }
    }
    std::copy(tmpSubSeq.begin(), tmpSubSeq.end(),
              std::back_insert_iterator<std::vector<std::vector<int>>>(sub));

    return longestSubSeq;
}

int getLongestIncSub(const std::vector<int> &sequence) {
    std::vector<std::vector<int>> sub;
    return getLongestIncSub(sequence, sequence.size() - 1, sub);
}

int main()
{
    std::vector<int> seq{0, 8, 2, 3, 7, 9};
    std::cout << getLongestIncSub(seq);
    return 0;
}

Ben yineleme tanımı max () yerine 0 <j <i ve dizi [i]> dizi [j] için maxLength (i) = 1 + max (maxLength (j)) olmalıdır.
Slothworks

1

İşte O (n ^ 2) algoritmasının Scala uygulaması:

object Solve {
  def longestIncrSubseq[T](xs: List[T])(implicit ord: Ordering[T]) = {
    xs.foldLeft(List[(Int, List[T])]()) {
      (sofar, x) =>
        if (sofar.isEmpty) List((1, List(x)))
        else {
          val resIfEndsAtCurr = (sofar, xs).zipped map {
            (tp, y) =>
              val len = tp._1
              val seq = tp._2
              if (ord.lteq(y, x)) {
                (len + 1, x :: seq) // reversely recorded to avoid O(n)
              } else {
                (1, List(x))
              }
          }
          sofar :+ resIfEndsAtCurr.maxBy(_._1)
        }
    }.maxBy(_._1)._2.reverse
  }

  def main(args: Array[String]) = {
    println(longestIncrSubseq(List(
      0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15)))
  }
}

1

İşte başka bir O (n ^ 2) JAVA uygulaması. Gerçek alt diziyi oluşturmak için özyineleme / notlama yok. Gerçek LIS'i her aşamada depolayan bir dize dizisi ve her öğe için LIS uzunluğunu depolayan bir dizi. Oldukça kolay. Bir göz atın:

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Created by Shreyans on 4/16/2015
 */

class LNG_INC_SUB//Longest Increasing Subsequence
{
    public static void main(String[] args) throws Exception
    {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        System.out.println("Enter Numbers Separated by Spaces to find their LIS\n");
        String[] s1=br.readLine().split(" ");
        int n=s1.length;
        int[] a=new int[n];//Array actual of Numbers
        String []ls=new String[n];// Array of Strings to maintain LIS for every element
        for(int i=0;i<n;i++)
        {
            a[i]=Integer.parseInt(s1[i]);
        }
        int[]dp=new int[n];//Storing length of max subseq.
        int max=dp[0]=1;//Defaults
        String seq=ls[0]=s1[0];//Defaults
        for(int i=1;i<n;i++)
        {
            dp[i]=1;
            String x="";
            for(int j=i-1;j>=0;j--)
            {
                //First check if number at index j is less than num at i.
                // Second the length of that DP should be greater than dp[i]
                // -1 since dp of previous could also be one. So we compare the dp[i] as empty initially
                if(a[j]<a[i]&&dp[j]>dp[i]-1)
                {
                    dp[i]=dp[j]+1;//Assigning temp length of LIS. There may come along a bigger LIS of a future a[j]
                    x=ls[j];//Assigning temp LIS of a[j]. Will append a[i] later on
                }
            }
            x+=(" "+a[i]);
            ls[i]=x;
            if(dp[i]>max)
            {
                max=dp[i];
                seq=ls[i];
            }
        }
        System.out.println("Length of LIS is: " + max + "\nThe Sequence is: " + seq);
    }
}

Kod iş başında: http://ideone.com/sBiOQx


0

Bu, Dinamik Programlama kullanılarak O (n ^ 2) olarak çözülebilir. Aynı Python kodu şöyle olurdu: -

def LIS(numlist):
    LS = [1]
    for i in range(1, len(numlist)):
        LS.append(1)
        for j in range(0, i):
            if numlist[i] > numlist[j] and LS[i]<=LS[j]:
                LS[i] = 1 + LS[j]
    print LS
    return max(LS)

numlist = map(int, raw_input().split(' '))
print LIS(numlist)

Giriş için:5 19 5 81 50 28 29 1 83 23

çıktı:[1, 2, 1, 3, 3, 3, 4, 1, 5, 3] 5

Çıktı listesinin list_index'i girdi listesinin list_index'idir. Çıktı listesindeki belirli bir list_index'teki değer, o list_index için en uzun artan alt sıra uzunluğunu gösterir.


0

java O (nlogn) uygulaması

import java.util.Scanner;

public class LongestIncreasingSeq {


    private static int binarySearch(int table[],int a,int len){

        int end = len-1;
        int beg = 0;
        int mid = 0;
        int result = -1;
        while(beg <= end){
            mid = (end + beg) / 2;
            if(table[mid] < a){
                beg=mid+1;
                result = mid;
            }else if(table[mid] == a){
                return len-1;
            }else{
                end = mid-1;
            }
        }
        return result;
    }

    public static void main(String[] args) {        

//        int[] t = {1, 2, 5,9,16};
//        System.out.println(binarySearch(t , 9, 5));
        Scanner in = new Scanner(System.in);
        int size = in.nextInt();//4;

        int A[] = new int[size];
        int table[] = new int[A.length]; 
        int k = 0;
        while(k<size){
            A[k++] = in.nextInt();
            if(k<size-1)
                in.nextLine();
        }        
        table[0] = A[0];
        int len = 1; 
        for (int i = 1; i < A.length; i++) {
            if(table[0] > A[i]){
                table[0] = A[i];
            }else if(table[len-1]<A[i]){
                table[len++]=A[i];
            }else{
                table[binarySearch(table, A[i],len)+1] = A[i];
            }            
        }
        System.out.println(len);
    }    
}

0

Bu, O (n ^ 2) içindeki bir Java uygulamasıdır. Ben sadece S = 'den X = daha küçük elemanı bulmak için İkili Arama kullanmadım. Ben sadece bir for döngüsü kullandım. İkili Arama kullanmak karmaşıklığı O (n logn) yapar

public static void olis(int[] seq){

    int[] memo = new int[seq.length];

    memo[0] = seq[0];
    int pos = 0;

    for (int i=1; i<seq.length; i++){

        int x = seq[i];

            if (memo[pos] < x){ 
                pos++;
                memo[pos] = x;
            } else {

                for(int j=0; j<=pos; j++){
                    if (memo[j] >= x){
                        memo[j] = x;
                        break;
                    }
                }
            }
            //just to print every step
            System.out.println(Arrays.toString(memo));
    }

    //the final array with the LIS
    System.out.println(Arrays.toString(memo));
    System.out.println("The length of lis is " + (pos + 1));

}

0

dizi elemanları ile en uzun artan sıra için java kodu çıkış

http://ideone.com/Nd2eba

/**
 **    Java Program to implement Longest Increasing Subsequence Algorithm
 **/

import java.util.Scanner;

/** Class  LongestIncreasingSubsequence **/
 class  LongestIncreasingSubsequence
{
    /** function lis **/
    public int[] lis(int[] X)
    {        
        int n = X.length - 1;
        int[] M = new int[n + 1];  
        int[] P = new int[n + 1]; 
        int L = 0;

        for (int i = 1; i < n + 1; i++)
        {
            int j = 0;

            /** Linear search applied here. Binary Search can be applied too.
                binary search for the largest positive j <= L such that 
                X[M[j]] < X[i] (or set j = 0 if no such value exists) **/

            for (int pos = L ; pos >= 1; pos--)
            {
                if (X[M[pos]] < X[i])
                {
                    j = pos;
                    break;
                }
            }            
            P[i] = M[j];
            if (j == L || X[i] < X[M[j + 1]])
            {
                M[j + 1] = i;
                L = Math.max(L,j + 1);
            }
        }

        /** backtrack **/

        int[] result = new int[L];
        int pos = M[L];
        for (int i = L - 1; i >= 0; i--)
        {
            result[i] = X[pos];
            pos = P[pos];
        }
        return result;             
    }

    /** Main Function **/
    public static void main(String[] args) 
    {    
        Scanner scan = new Scanner(System.in);
        System.out.println("Longest Increasing Subsequence Algorithm Test\n");

        System.out.println("Enter number of elements");
        int n = scan.nextInt();
        int[] arr = new int[n + 1];
        System.out.println("\nEnter "+ n +" elements");
        for (int i = 1; i <= n; i++)
            arr[i] = scan.nextInt();

        LongestIncreasingSubsequence obj = new LongestIncreasingSubsequence(); 
        int[] result = obj.lis(arr);       

        /** print result **/ 

        System.out.print("\nLongest Increasing Subsequence : ");
        for (int i = 0; i < result.length; i++)
            System.out.print(result[i] +" ");
        System.out.println();
    }
}

0

Bu dinamik programlama kullanılarak O (n ^ 2) olarak çözülebilir.

Giriş elemanlarını sırayla işleyin ve her eleman için bir tuple listesi bulundurun. Her tuple (A, B), i öğesi için şunları gösterir: A = i ile biten en uzun artan alt sekans uzunluğu ve B = listeden [i] en uzun artan alt sekans sonundaki liste [i] 'nin öncülü dizini ].

1. öğeden başlayarak, 1. öğenin demet listesi i öğesi için [(1,0)] olacaktır, 0..i listesini tarayın ve [k] listesi [k] <liste [i] , i öğesi için A'nın değeri, Ai, Ak + 1 ve Bi, k olacaktır. Bu tür birden fazla öğe varsa, bunları öğe i için tuples listesine ekleyin.

Sonunda, maksimum A değerine (elemanda biten LIS uzunluğu) ve geri izlemeye sahip tüm öğeleri bulun ve listeyi almak için tuples'ı kullanın.

Aynı kodu http://www.edufyme.com/code/?id=66f041e16a60928b05a7e228a89c3799 adresinde paylaştım


3
Bağlantı kesilebileceğinden kodu cevabınıza eklemelisiniz.
NathanOliver

0

O (n ^ 2) java uygulaması:

void LIS(int arr[]){
        int maxCount[]=new int[arr.length];
        int link[]=new int[arr.length];
        int maxI=0;
        link[0]=0;
        maxCount[0]=0;

        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < i; j++) {
                if(arr[j]<arr[i] && ((maxCount[j]+1)>maxCount[i])){
                    maxCount[i]=maxCount[j]+1;
                    link[i]=j;
                    if(maxCount[i]>maxCount[maxI]){
                        maxI=i;
                    }
                }
            }
        }


        for (int i = 0; i < link.length; i++) {
            System.out.println(arr[i]+"   "+link[i]);
        }
        print(arr,maxI,link);

    }

    void print(int arr[],int index,int link[]){
        if(link[index]==index){
            System.out.println(arr[index]+" ");
            return;
        }else{
            print(arr, link[index], link);
            System.out.println(arr[index]+" ");
        }
    }

0
def longestincrsub(arr1):
    n=len(arr1)
    l=[1]*n
    for i in range(0,n):
        for j in range(0,i)  :
            if arr1[j]<arr1[i] and l[i]<l[j] + 1:
                l[i] =l[j] + 1
    l.sort()
    return l[-1]
arr1=[10,22,9,33,21,50,41,60]
a=longestincrsub(arr1)
print(a)

bunu O (nlogn) zamanında çözmenin bir yolu olsa da (bu O (n ^ 2) zamanında çözülür) ama yine de bu şekilde dinamik programlama yaklaşımı da iyidir.


0

İşte İkili Arama kullanarak Leetcode çözümüm: ->

class Solution:
    def binary_search(self,s,x):
        low=0
        high=len(s)-1
        flag=1
        while low<=high:
              mid=(high+low)//2
              if s[mid]==x:
                 flag=0
                 break
              elif s[mid]<x:
                  low=mid+1
              else:
                 high=mid-1
        if flag:
           s[low]=x
        return s

    def lengthOfLIS(self, nums: List[int]) -> int:
         if not nums:
            return 0
         s=[]
         s.append(nums[0])
         for i in range(1,len(nums)):
             if s[-1]<nums[i]:
                s.append(nums[i])
             else:
                 s=self.binary_search(s,nums[i])
         return len(s)

0

O (nlog (n)) zaman karmaşıklığına sahip C ++ 'da en basit LIS çözümü

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

// binary search (If value not found then it will return the index where the value should be inserted)
int ceilBinarySearch(vector<int> &a,int beg,int end,int value)
{
    if(beg<=end)
    {
        int mid = (beg+end)/2;
        if(a[mid] == value)
            return mid;
        else if(value < a[mid])
            return ceilBinarySearch(a,beg,mid-1,value);
        else
            return ceilBinarySearch(a,mid+1,end,value);

    return 0;
    }

    return beg;

}
int lis(vector<int> arr)
{
    vector<int> dp(arr.size(),0);
    int len = 0;
    for(int i = 0;i<arr.size();i++)
    {
        int j = ceilBinarySearch(dp,0,len-1,arr[i]);
        dp[j] = arr[i];
        if(j == len)
            len++;

    }
    return len;
}

int main()
{
    vector<int> arr  {2, 5,-1,0,6,1,2};
    cout<<lis(arr);
    return 0;
}

ÇIKTI:
4


0

En Uzun Artan Alt Sıra (Java)

import java.util.*;

class ChainHighestValue implements Comparable<ChainHighestValue>{
    int highestValue;
    int chainLength;
    ChainHighestValue(int highestValue,int chainLength) {
        this.highestValue = highestValue;
        this.chainLength = chainLength;
    }
    @Override
    public int compareTo(ChainHighestValue o) {
       return this.chainLength-o.chainLength;
    }

}


public class LongestIncreasingSubsequenceLinkedList {


    private static LinkedList<Integer> LongestSubsequent(int arr[], int size){
        ArrayList<LinkedList<Integer>> seqList=new ArrayList<>();
        ArrayList<ChainHighestValue> valuePairs=new ArrayList<>();
        for(int i=0;i<size;i++){
            int currValue=arr[i];
            if(valuePairs.size()==0){
                LinkedList<Integer> aList=new LinkedList<>();
                aList.add(arr[i]);
                seqList.add(aList);
                valuePairs.add(new ChainHighestValue(arr[i],1));

            }else{
                try{
                    ChainHighestValue heighestIndex=valuePairs.stream().filter(e->e.highestValue<currValue).max(ChainHighestValue::compareTo).get();
                    int index=valuePairs.indexOf(heighestIndex);
                    seqList.get(index).add(arr[i]);
                    heighestIndex.highestValue=arr[i];
                    heighestIndex.chainLength+=1;

                }catch (Exception e){
                    LinkedList<Integer> aList=new LinkedList<>();
                    aList.add(arr[i]);
                    seqList.add(aList);
                    valuePairs.add(new ChainHighestValue(arr[i],1));
                }
            }
        }
        ChainHighestValue heighestIndex=valuePairs.stream().max(ChainHighestValue::compareTo).get();
        int index=valuePairs.indexOf(heighestIndex);
        return seqList.get(index);
    }

    public static void main(String[] args){
        int arry[]={5,1,3,6,11,30,32,5,3,73,79};
        //int arryB[]={3,1,5,2,6,4,9};
        LinkedList<Integer> LIS=LongestSubsequent(arry, arry.length);
        System.out.println("Longest Incrementing Subsequence:");
        for(Integer a: LIS){
            System.out.print(a+" ");
        }

    }
}

0

Java'da Dinamik Programlama ve Hatırlatma kullanarak LIS uyguladım. Kod ile birlikte karmaşıklık hesaplama yaptım yani neden O (n Log (base2) n). Teorik veya mantıksal açıklamaların iyi olduğunu düşündüğümden, pratik gösteriler anlamak için her zaman daha iyidir.

package com.company.dynamicProgramming;

import java.util.HashMap;
import java.util.Map;

public class LongestIncreasingSequence {

    static int complexity = 0;

    public static void main(String ...args){


        int[] arr = {10, 22, 9, 33, 21, 50, 41, 60, 80};
        int n = arr.length;

        Map<Integer, Integer> memo = new HashMap<>();

        lis(arr, n, memo);

        //Display Code Begins
        int x = 0;
        System.out.format("Longest Increasing Sub-Sequence with size %S is -> ",memo.get(n));
        for(Map.Entry e : memo.entrySet()){

            if((Integer)e.getValue() > x){
                System.out.print(arr[(Integer)e.getKey()-1] + " ");
                x++;
            }
        }
        System.out.format("%nAnd Time Complexity for Array size %S is just %S ", arr.length, complexity );
        System.out.format( "%nWhich is equivalent to O(n Log n) i.e. %SLog(base2)%S is %S",arr.length,arr.length, arr.length * Math.ceil(Math.log(arr.length)/Math.log(2)));
        //Display Code Ends

    }



    static int lis(int[] arr, int n, Map<Integer, Integer> memo){

        if(n==1){
            memo.put(1, 1);
            return 1;
        }

        int lisAti;
        int lisAtn = 1;

        for(int i = 1; i < n; i++){
            complexity++;

            if(memo.get(i)!=null){
                lisAti = memo.get(i);
            }else {
                lisAti = lis(arr, i, memo);
            }

            if(arr[i-1] < arr[n-1] && lisAti +1 > lisAtn){
                lisAtn = lisAti +1;
            }
        }

        memo.put(n, lisAtn);
        return lisAtn;

    }
}

Ben yukarıdaki kodu koştu iken -

Longest Increasing Sub-Sequence with size 6 is -> 10 22 33 50 60 80 
And Time Complexity for Array size 9 is just 36 
Which is equivalent to O(n Log n) i.e. 9Log(base2)9 is 36.0
Process finished with exit code 0


Giriş için yanlış cevap verir: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
ahadcse

0

En Uzun Artan Alt Diziyi Bulmak İçin O (NLog (N)) Yaklaşımı
ith öğesinin, ai boyutlu alt dizinin sona erebileceği mümkün olan en küçük sayı olduğu bir diziyi muhafaza edelim.

Amaç olarak, en çok oy alan cevap zaten açıkladığı gibi daha fazla ayrıntıdan kaçınıyorum, ancak bu teknik sonunda (en azından c ++) set veri yapısını kullanarak düzgün bir uygulamaya yol açar.

İşte c ++ 'da uygulama (kesinlikle en uzun alt sekans boyutunun artması gerektiğini varsayarsak)

#include <bits/stdc++.h> // gcc supported header to include (almost) everything
using namespace std;
typedef long long ll;

int main()
{
  ll n;
  cin >> n;
  ll arr[n];
  set<ll> S;

  for(ll i=0; i<n; i++)
  {
    cin >> arr[i];
    auto it = S.lower_bound(arr[i]);
    if(it != S.end())
      S.erase(it);
    S.insert(arr[i]);
  }

  cout << S.size() << endl; // Size of the set is the required answer

  return 0;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.