Как найти убывающая подпоследовательность

Проблема самой длинной убывающей подпоследовательности состоит в том, чтобы найти подпоследовательность заданной последовательности, в которой элементы подпоследовательности отсортированы в порядке от высшего к низшему, и в которой подпоследовательность является максимально возможной. Эта подпоследовательность не обязательно непрерывна или уникальна.

Обратите внимание, что проблема конкретно нацелена подпоследовательности которые не обязательно должны быть непрерывными, т. е. не требуется, чтобы подпоследовательности занимали последовательные позиции в исходных последовательностях.

Например, рассмотрим следующую подпоследовательность:

[0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

 
Самая длинная убывающая подпоследовательность [12, 10, 9, 5, 3], длина которого равна 5; входная последовательность не имеет 6-членных убывающих подпоследовательностей.

 
Самая длинная убывающая подпоследовательность в этом примере не уникальна: например, [12, 10, 6, 5, 3] — еще одна убывающая подпоследовательность той же длины в той же входной последовательности.

Потренируйтесь в этой проблеме

Мы можем использовать рекурсия Для решения этой проблемы. Для каждого элемента есть две возможности:

  1. Включить текущий элемент в LDS, если он меньше, чем предыдущий элемент в LDS, и повторить для остальных элементов.
  2. Исключить текущий элемент из LDS и повторить для остальных элементов.

Наконец, верните максимальное значение, которое мы получим, включив или исключив текущий элемент. Базовым случаем рекурсии будет отсутствие элементов. Ниже приведена реализация этой идеи на C++, Java и Python:

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

#include <iostream>

#include <vector>

#include <climits>

using namespace std;

// Функция для нахождения длины самой длинной убывающей подпоследовательности

int LDS(vector<int> const &nums, int i, int prev)

{

    // Базовый случай: ничего не осталось

    if (i == nums.size()) {

        return 0;

    }

    // случай 1: исключить текущий элемент и обработать

    // оставшиеся элементы

    int excl = LDS(nums, i + 1, prev);

    // случай 2: включить текущий элемент, если он меньше

    // чем предыдущий элемент в LDS

    int incl = 0;

    if (nums[i] < prev) {

        incl = 1 + LDS(nums, i + 1, nums[i]);

    }

    // вернуть максимум из двух вышеперечисленных вариантов

    return max(incl, excl);

}

int main()

{

    vector<int> nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

    cout << «The length of the LDS is « << LDS(nums, 0, INT_MAX);

    return 0;

}

Скачать  Выполнить код

результат:

The length of the LDS is 5

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

class Main

{

    // Функция для нахождения длины самой длинной убывающей подпоследовательности

    // подмассива `nums[i…n)`

    public static int LDS(int[] nums, int i, int prev)

    {

        // Базовый случай: ничего не осталось

        if (i == nums.length) {

            return 0;

        }

        // случай 1: исключить текущий элемент и обработать

        // оставшиеся элементы

        int excl = LDS(nums, i + 1, prev);

        // случай 2: включить текущий элемент, если он меньше

        // чем предыдущий элемент в LDS

        int incl = 0;

        if (nums[i] < prev) {

            incl = 1 + LDS(nums, i + 1, nums[i]);

        }

        // вернуть максимум из двух вышеперечисленных вариантов

        return Integer.max(incl, excl);

    }

    public static void main(String[] args)

    {

        int[] nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

        System.out.println(«The length of the LDS is « +

                    LDS(nums, 0, Integer.MAX_VALUE));

    }

}

Скачать  Выполнить код

результат:

The length of the LDS is 5

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

import sys

# Функция для нахождения длины самой длинной убывающей подпоследовательности

# подсписка `nums[i…n)`

def LDS(nums, i=0, prev=sys.maxsize):

    # Базовый вариант: ничего не осталось

    if i == len(nums):

        return 0

    #, случай 1: исключить текущий элемент и обработать

    # остальные элементы

    excl = LDS(nums, i + 1, prev)

    #, случай 2: включить текущий элемент, если он меньше

    #, чем предыдущий элемент в LDS

    incl = 0

    if nums[i] < prev:

        incl = 1 + LDS(nums, i + 1, nums[i])

    # возвращает максимум из двух вышеперечисленных вариантов.

    return max(incl, excl)

if __name__ == ‘__main__’:

    nums = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

    print(‘The length of the LDS is’, LDS(nums))

Скачать  Выполнить код

результат:

The length of the LDS is 5

Временная сложность приведенного выше решения экспоненциальна и занимает место в стеке вызовов.
 

 
Проблема имеет оптимальное основание. Это означает, что проблема может быть разбита на более мелкие, простые “подзадачи”, которые затем могут быть разделены на еще более простые, более мелкие подзадачи, пока решение не станет тривиальным. Приведенное выше решение также демонстрирует перекрывающиеся подзадачи. Если мы нарисуем дерево рекурсии решения, мы увидим, что одни и те же подзадачи вычисляются повторно.

Мы знаем, что задачи с оптимальной структурой и перекрывающимися подзадачами могут быть решены с помощью динамического программирования, где решения подзадач памятка, а не вычисляется повторно. памяткаИзмененная версия следует нисходящему подходу, поскольку сначала мы разбиваем задачу на подзадачи, а затем вычисляем и сохраняем значения.

 
Мы также можем решить эту проблему восходящим способом. При подходе «снизу вверх» мы сначала решаем меньшие подзадачи, а затем на их основе решаем более крупные подзадачи. Следующий восходящий подход вычисляет L[i], для каждого 0 <= i < n, в котором хранится длина самой длинной убывающей подпоследовательности подмассива nums[0…i] что заканчивается nums[i]. Вычислять L[i], рассмотрим LDS всех меньших значений i (сказать j) уже вычислено и выбрать максимальное L[j], куда nums[j] больше, чем текущий элемент nums[i]. У него такое же асимптотическое время выполнения, как и у Memoization, но нет накладных расходов на рекурсию.

Ниже приведена реализация этой идеи на C++, Java и Python:

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

#include <iostream>

#include <vector>

#include <climits>

using namespace std;

// Итерационная функция для нахождения длины самой длинной убывающей подпоследовательности

// данного массива

int LDS(vector<int> const &nums)

{

    int n = nums.size();

    // базовый вариант

    if (n == 0) {

        return 0;

    }

    // массив для хранения решения подзадачи. `L[i]` хранит длину

    // самой длинной убывающей подпоследовательности, заканчивающейся на `nums[i]`

    vector<int> L(n);

    // самая длинная убывающая подпоследовательность, оканчивающаяся на `nums[0]`, имеет длину 1

    L[0] = 1;

    // начинаем со второго элемента массива

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

    {

        // делаем для каждого элемента подмассива `nums[0…i-1]`

        for (int j = 0; j < i; j++)

        {

            // найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

            // где `nums[j]` больше, чем текущий элемент `nums[i]`

            if (nums[j] > nums[i] && L[j] > L[i]) {

                L[i] = L[j];

            }

        }

        // включить `nums[i]` в LDS

        L[i]++;

    }

    // найти самую длинную убывающую подпоследовательность (имеющую максимальную длину)

    int lis = INT_MIN;

    for (int x: L) {

        lis = max(lis, x);

    }

    return lis;

}

int main()

{

    vector<int> nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

    cout << «The length of the LDS is « << LDS(nums);

    return 0;

}

Скачать  Выполнить код

результат:

The length of the LDS is 5

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

import java.util.Arrays;

class Main

{

    // Итерационная функция для нахождения длины самой длинной убывающей подпоследовательности

    // данного массива

    public static int LDS(int[] nums)

    {

        // базовый вариант

        if (nums == null || nums.length == 0) {

            return 0;

        }

        // массив для хранения решения подзадачи. `L[i]` хранит длину

        // самой длинной убывающей подпоследовательности, заканчивающейся на `nums[i]`

        int[] L = new int[nums.length];

        // самая длинная убывающая подпоследовательность, оканчивающаяся на `nums[0]`, имеет длину 1

        L[0] = 1;

        // начинаем со второго элемента массива

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

        {

            // делаем для каждого элемента подмассива `nums[0…i-1]`

            for (int j = 0; j < i; j++)

            {

                // найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

                // где `nums[j]` больше, чем текущий элемент `nums[i]`

                if (nums[j] > nums[i] && L[j] > L[i]) {

                    L[i] = L[j];

                }

            }

            // включить `nums[i]` в LDS

            L[i]++;

        }

        // вернуть самую длинную убывающую подпоследовательность (имеющую максимальную длину)

        return Arrays.stream(L).max().getAsInt();

    }

    public static void main(String[] args)

    {

        int[] nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

        System.out.println(«The length of the LDS is « + LDS(nums));

    }

}

Скачать  Выполнить код

результат:

The length of the LDS is 5

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

# Итерационная функция для нахождения длины самой длинной убывающей подпоследовательности

# данного списка

def LDS(nums):

    if not nums:

        return 0

    # Список # для хранения решений подзадач. `L[i]` хранит длину

    # самой длинной убывающей подпоследовательности, которая заканчивается на `nums[i]`

    L = [0] * len(nums)

    # самая длинная убывающая подпоследовательность, оканчивающаяся на `nums[0]`, имеет длину 1

    L[0] = 1

    # старт со второго элемента в списке

    for i in range(1, len(nums)):

        # сделать для каждого элемента в подсписке `nums[0…i-1]`

        for j in range(i):

            # найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

            #, где `nums[j]` больше, чем текущий элемент `nums[i]`

            if nums[j] > nums[i] and L[j] > L[i]:

                L[i] = L[j]

        # включает `nums[i]` в LDS

        L[i] = L[i] + 1

    # возвращает самую длинную убывающую подпоследовательность (имеющую максимальную длину)

    return max(L)

if __name__ == ‘__main__’:

    nums = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

    print(‘The length of the LDS is’, LDS(nums))

Скачать  Выполнить код

результат:

The length of the LDS is 5

Временная сложность приведенного выше решения равна O(n2) и требует O(n) дополнительное пространство, где n — размер заданной последовательности.

Как распечатать ЛДС?

Рассмотренные выше методы печатают только длину LDS, но не печатают саму LDS. Чтобы распечатать LDS, мы должны сохранить самую длинную убывающую подпоследовательность в таблице поиска, а не хранить только длину LDS.

 
Например, рассмотрим следующий массив:

nums[] = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

Самая длинная убывающая подпоследовательность LDS[i] подмассива nums[0…i] что заканчивается nums[i] находятся:

LDS[0] — 0
LDS[1] — 8
LDS[2] — 8 4
LDS[3] — 12
LDS[4] — 8 4 2
LDS[5] — 12 10
LDS[6] — 12 10 6
LDS[7] — 14
LDS[8] — 8 4 2 1
LDS[9] — 12 10 9
LDS[10] — 12 10 6 5
LDS[11] — 14 13
LDS[12] — 12 10 6 5 3
LDS[13] — 14 13 11
LDS[14] — 12 10 9 7
LDS[15] — 15

Алгоритм может быть реализован следующим образом на C++, Java и Python:

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

#include <iostream>

#include <vector>

using namespace std;

// Итерационная функция для поиска самой длинной убывающей подпоследовательности

// данного массива

void findLDS(vector<int> const &nums)

{

    int n = nums.size();

    // базовый вариант

    if (n == 0) {

        return;

    }

    // `LDS[i]` хранит самую длинную убывающую подпоследовательность подмассива

    // `nums[0…i]`, оканчивающийся на `nums[i]`

    vector<vector<int>> LDS(n, vector<int>());

    // `LDS[0]` обозначает самую длинную убывающую подпоследовательность, заканчивающуюся на `nums[0]`

    LDS[0].push_back(nums[0]);

    // начинаем со второго элемента массива

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

    {

        // делаем для каждого элемента подмассива `nums[0…i-1]`

        for (int j = 0; j < i; j++)

        {

            // найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

            // где `nums[j]` больше, чем текущий элемент `nums[i]`

            if (nums[j] > nums[i] && LDS[j].size() > LDS[i].size()) {

                LDS[i] = LDS[j];

            }

        }

        // включить `nums[i]` в `LDS[i]`

        LDS[i].push_back(nums[i]);

    }

    // раскомментируйте следующий код, чтобы напечатать содержимое `LDS`

    /* for (int i = 0; i < n; i++)

    {

        cout << «LDS[» << i << «] — «;

        for (int j: LDS[i]) {

            cout << j << » «;

        }

        cout << конец;

    } */

    // `j` будет содержать индекс LDS

    int j = 0;

    for (int i = 0; i < n; i++)

    {

        if (LDS[j].size() < LDS[i].size()) {

            j = i;

        }

    }

    // печать LDS

    for (int i: LDS[j]) {

        cout << i << » «;

    }

}

int main()

{

    vector<int> nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

    findLDS(nums);

    return 0;

}

Скачать  Выполнить код

результат:

12 10 6 5 3

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

import java.util.ArrayList;

import java.util.List;

class Main

{

    // Итерационная функция для поиска самой длинной убывающей подпоследовательности

    // данного массива

    public static void findLDS(int[] nums)

    {

        // базовый вариант

        if (nums == null || nums.length == 0) {

            return;

        }

        // `LDS[i]` хранит самую длинную убывающую подпоследовательность подмассива

        // `nums[0…i]`, оканчивающийся на `nums[i]`

        List<List<Integer>> LDS = new ArrayList<>();

        for (int i = 0; i < nums.length; i++) {

            LDS.add(new ArrayList<>());

        }

        // `LDS[0]` обозначает самую длинную убывающую подпоследовательность, заканчивающуюся на `nums[0]`

        LDS.get(0).add(nums[0]);

        // начинаем со второго элемента массива

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

        {

            // делаем для каждого элемента подмассива `nums[0…i-1]`

            for (int j = 0; j < i; j++)

            {

                // найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

                // где `nums[j]` больше, чем текущий элемент `nums[i]`

                if (nums[j] > nums[i] && LDS.get(j).size() > LDS.get(i).size()) {

                    LDS.set(i, new ArrayList<>(LDS.get(j)));

                }

            }

            // включить `nums[i]` в `LDS[i]`

            LDS.get(i).add(nums[i]);

        }

        // раскомментируйте следующий код, чтобы напечатать содержимое `LDS`

        /*for (int i = 0; i < nums.length; i++) {

            System.out.println(«LDS[» + i + «] — » + LDS.get(i));

        }*/

        // `j` будет содержать индекс LDS

        int j = 0;

        for (int i = 0; i < nums.length; i++)

        {

            if (LDS.get(j).size() < LDS.get(i).size()) {

                j = i;

            }

        }

        // печать LDS

        System.out.print(LDS.get(j));

    }

    public static void main(String[] args)

    {

        int[] nums = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };

        findLDS(nums);

    }

}

Скачать  Выполнить код

результат:

[12, 10, 6, 5, 3]

Python

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

# Итеративная функция для поиска самой длинной убывающей подпоследовательности заданного списка

def findLDS(nums):

    # Базовый вариант

    if not nums:

        return

    # `LDS[i]` хранит самую длинную убывающую подпоследовательность подсписка

    # `nums[0…i]`, оканчивающийся на `nums[i]`

    LDS = [[] for _ in range(len(nums))]

    # `LDS[0]` обозначает самую длинную убывающую подпоследовательность, заканчивающуюся на `nums[0]`

    LDS[0].append(nums[0])

    # старт со второго элемента в списке

    for i in range(1, len(nums)):

        # сделать для каждого элемента в подсписке `nums[0…i-1]`

        for j in range(i):

            # найти самую длинную убывающую подпоследовательность, которая заканчивается на `nums[j]`

            #, где `nums[j]` больше, чем текущий элемент `nums[i]`

            if nums[j] > nums[i] and len(LDS[j]) > len(LDS[i]):

                LDS[i] = LDS[j].copy()

        # включает `nums[i]` в `LDS[i]`

        LDS[i].append(nums[i])

    # `j` будет содержать индекс LDS

    j = 0

    for i in range(len(nums)):

        if len(LDS[j]) < len(LDS[i]):

            j = i

    # печать ЛДС

    print(LDS[j])

if __name__ == ‘__main__’:

    nums = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

    findLDS(nums)

Скачать  Выполнить код

результат:

[12, 10, 6, 5, 3]

Временная сложность приведенного выше решения равна O(n2) и требует O(n2) дополнительное пространство, где n — размер заданной последовательности.

Given an array of N integers, find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in strictly decreasing order. 
Examples:  

Input: arr[] = [15, 27, 14, 38, 63, 55, 46, 65, 85] 
Output:
Explanation: The longest decreasing subsequence is {63, 55, 46} 
Input: arr[] = {50, 3, 10, 7, 40, 80} 
Output:
Explanation: The longest decreasing subsequence is {50, 10, 7} 

The problem can be solved using Dynamic Programming
Optimal Substructure: 
Let arr[0…n-1] be the input array and lds[i] be the length of the LDS ending at index i such that arr[i] is the last element of the LDS. 
Then, lds[i] can be recursively written as: 

lds[i] = 1 + max(lds[j]) where i > j > 0 and arr[j] > arr[i] or 
lds[i] = 1, if no such j exists.

To find the LDS for a given array, we need to return max(lds[i]) where n > i > 0.  

C++

#include <bits/stdc++.h>

using namespace std;

int lds(int arr[], int n)

{

    int lds[n];

    int i, j, max = 0;

    for (i = 0; i < n; i++)

        lds[i] = 1;

    for (i = 1; i < n; i++)

        for (j = 0; j < i; j++)

            if (arr[i] < arr[j] && lds[i] < lds[j] + 1)

                lds[i] = lds[j] + 1;

    for (i = 0; i < n; i++)

        if (max < lds[i])

            max = lds[i];

    return max;

}

int main()

{

    int arr[] = { 15, 27, 14, 38, 63, 55, 46, 65, 85 };

    int n = sizeof(arr) / sizeof(arr[0]);

    cout << "Length of LDS is " << lds(arr, n);

    return 0;

}

Java

import java.io.*;

class GFG

{

static int lds(int arr[], int n)

{

    int lds[] = new int[n];

    int i, j, max = 0;

    for (i = 0; i < n; i++)

        lds[i] = 1;

    for (i = 1; i < n; i++)

        for (j = 0; j < i; j++)

            if (arr[i] < arr[j] &&

                         lds[i] < lds[j] + 1)

                lds[i] = lds[j] + 1;

    for (i = 0; i < n; i++)

        if (max < lds[i])

            max = lds[i];

    return max;

}

public static void main (String[] args)

{

    int arr[] = { 15, 27, 14, 38,

                  63, 55, 46, 65, 85 };

    int n = arr.length;

    System.out.print("Length of LDS is " +

                             lds(arr, n));

}

}

Python 3

def lds(arr, n):

    lds = [0] * n

    max = 0

    for i in range(n):

        lds[i] = 1

    for i in range(1, n):

        for j in range(i):

            if (arr[i] < arr[j] and

                lds[i] < lds[j] + 1):

                lds[i] = lds[j] + 1

    for i in range(n):

        if (max < lds[i]):

            max = lds[i]

    return max

if __name__ == "__main__":

    arr = [ 15, 27, 14, 38,

            63, 55, 46, 65, 85 ]

    n = len(arr)

    print("Length of LDS is", lds(arr, n))

C#

using System;

class GFG

{

static int lds(int []arr, int n)

{

    int []lds = new int[n];

    int i, j, max = 0;

    for (i = 0; i < n; i++)

        lds[i] = 1;

    for (i = 1; i < n; i++)

        for (j = 0; j < i; j++)

            if (arr[i] < arr[j] &&

                        lds[i] < lds[j] + 1)

                lds[i] = lds[j] + 1;

    for (i = 0; i < n; i++)

        if (max < lds[i])

            max = lds[i];

    return max;

}

public static void Main ()

{

    int []arr = { 15, 27, 14, 38,

                63, 55, 46, 65, 85 };

    int n = arr.Length;

    Console.Write("Length of LDS is " +

                          lds(arr, n));

}

}

PHP

<?php

function lds($arr, $n)

{

    $lds = array();

    $i; $j; $max = 0;

    for ($i = 0; $i < $n; $i++)

        $lds[$i] = 1;

    for ($i = 1; $i < $n; $i++)

        for ($j = 0; $j < $i; $j++)

            if ($arr[$i] < $arr[$j] and

                $lds[$i] < $lds[$j] + 1)

                {

                    $lds[$i] = $lds[$j] + 1;

                }

    for ($i = 0; $i < $n; $i++)

        if ($max < $lds[$i])

            $max = $lds[$i];

    return $max;

}

$arr = array(15, 27, 14, 38, 63,

             55, 46, 65, 85);

$n = count($arr);

echo "Length of LDS is " ,

            lds($arr, $n);

?>

Javascript

<script>

    function lds(arr,n)

    {

        let lds = new Array(n);

    let i, j, max = 0;

    for (i = 0; i < n; i++)

        lds[i] = 1;

    for (i = 1; i < n; i++)

        for (j = 0; j < i; j++)

            if (arr[i] < arr[j] &&

                         lds[i] < lds[j] + 1)

                lds[i] = lds[j] + 1;

    for (i = 0; i < n; i++)

        if (max < lds[i])

            max = lds[i];

    return max;

    }

    let arr=[15, 27, 14, 38,

                  63, 55, 46, 65, 85 ];

    let n = arr.length;

    document.write("Length of LDS is " +

                             lds(arr, n));

</script>

Output :

Length of LDS is 3

Time Complexity: O(n2
Auxiliary Space: O(n)
Related Article: https://www.geeksforgeeks.org/longest-increasing-subsequence/

Longest Decreasing Subsequence in O(n*log(n)) :

Another approach to finding the Longest Decreasing Subsequence is using the Longest Increasing Subsequence approach in n*log(n) complexity. Here is the link to find the details of the approach with O(n*log(n)) complexity https://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/.

We can observe that the length of the Longest Decreasing Subsequence of any array is same as the length of the Longest Increasing Subsequence of that array if we multiply all elements by -1.

For example:

arr[] = [15, 27, 14, 38, 63, 55, 46, 65, 85] 
then the length of longest decreasing subsequence of this array is same as length of longest increasing subsequence of arr[]=[-15, -27, -14, -38, -63, -55, -46, -65, -85]

In both cases the length is 3.

Steps to solve this problem:

1. Check if array is zero than return zero.

2. Declare a vector tail of array size.

3. Declare a variable length=1.

4. Initialize tail[0]=v[0].

5. Iterate through i=1 till size of array:

    *Initialize auto b=tail.begin and e=tail.begin+length.

    *Initialize auto it to lower bound of v[i].

    *Check if it is equal to tail.begin+length than tail[length++]=v[i].

    *Else update value at it =v[i].

6. Return length.

Below is the code of the above approach.

C++

#include <bits/stdc++.h>

using namespace std;

int LongestIncreasingSubsequenceLength(vector<int>& v)

{

    if (v.size() == 0)

        return 0;

    vector<int> tail(v.size(), 0);

    int length = 1;

    tail[0] = v[0];

    for (int i = 1; i < v.size(); i++) {

        auto b = tail.begin(), e = tail.begin() + length;

        auto it = lower_bound(b, e, v[i]);

        if (it == tail.begin() + length)

            tail[length++] = v[i];

        else

            *it = v[i];

    }

    return length;

}

int main()

{

    vector<int> v{ 15, 27, 14, 38, 63, 55, 46, 65, 85 };

    int n=v.size();

    for(int i=0;i<n;i++)

    {

        v[i]=-1*v[i];

    }

    cout

        << "Length of Longest Decreasing Subsequence is "

        << LongestIncreasingSubsequenceLength(v);

    return 0;

}

Java

import java.io.*;

import java.lang.Math;

import java.util.*;

class LIS {

    static int LongestIncreasingSubsequenceLength(int v[])

    {

        if (v.length == 0)

            return 0;

        int[] tail = new int[v.length];

        int length = 1;

        tail[0] = v[0];

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

            if (v[i] > tail[length - 1]) {

                tail[length++] = v[i];

            }

            else {

                int idx = Arrays.binarySearch(

                    tail, 0, length - 1, v[i]);

                if (idx < 0)

                    idx = -1 * idx - 1;

                tail[idx] = v[i];

            }

        }

        return length;

    }

    public static void main(String[] args)

    {

        int v[] = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };

        int n=v.length;

        for(int i=0;i<n;i++)

        {

            v[i]=-1*v[i];

        }

        System.out.println(

            "Length of Longest Decreasing Subsequence is "

            + LongestIncreasingSubsequenceLength(v));

    }

}

Python3

from bisect import bisect_left

def LongestIncreasingSubsequenceLength(v):

    n = len(v)

    if n == 0:

        return 0

    tail = [0] * n

    length = 1

    tail[0] = v[0]

    for i in range(1, n):

        j = bisect_left(tail, v[i], 0, length)

        if j == length:

            tail[length] = v[i]

            length += 1

        else:

            tail[j] = v[i]

    return length

v = [15, 27, 14, 38, 63, 55, 46, 65, 85]

v = [-x for x in v]

print("Length of Longest Decreasing Subsequence is", LongestIncreasingSubsequenceLength(v))

C#

using System;

using System.Linq;

class LIS {

    static int LongestIncreasingSubsequenceLength(int[] v)

    {

        if (v.Length == 0)

            return 0;

        int[] tail = new int[v.Length];

        int length = 1;

        tail[0] = v[0];

        for (int i = 1; i < v.Length; i++) {

            if (v[i] > tail[length - 1]) {

                tail[length++] = v[i];

            }

            else {

                int idx = Array.BinarySearch(

                    tail, 0, length - 1, v[i]);

                if (idx < 0)

                    idx = ~idx;

                tail[idx] = v[i];

            }

        }

        return length;

    }

    public static void Main(string[] args)

    {

        int[] v = { 2, 5, 3, 7, 11, 8, 10, 13, 6 };

        int n = v.Length;

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

            v[i] = -1 * v[i];

        }

        Console.WriteLine(

            "Length of Longest Decreasing Subsequence is "

            + LongestIncreasingSubsequenceLength(v));

    }

}

Javascript

function LongestIncreasingSubsequenceLength(v) {

    if (v.length === 0) {

        return 0;

    }

    const tail = new Array(v.length).fill(0);

    let length = 1;

    tail[0] = v[0];

    for (let i = 1; i < v.length; i++) {

        let b = 0, e = length;

        let mid;

        while (b < e) {

            mid = Math.floor((b + e) / 2);

            if (tail[mid] < v[i]) {

                b = mid + 1;

            } else {

                e = mid;

            }

        }

        if (b === length) {

            tail[length++] = v[i];

        } else {

            tail[b] = v[i];

        }

    }

    return length;

}

let v = [15, 27, 14, 38, 63, 55, 46, 65, 85];

let n = v.length;

for (let i = 0; i < n; i++) {

    v[i] = -v[i];

}

console.log("Length of Longest Decreasing Subsequence is " +

    LongestIncreasingSubsequenceLength(v));

Output

Length of Longest Decreasing Subsequence is 3

Time Complexity: O(n*logn)
Auxiliary Space: O(n)

Last Updated :
28 Feb, 2023

Like Article

Save Article

1. Название Описание

[Вопрос 1] Найти самый длинный из массивапрерывистыйНисходящая подпоследовательность

[Вопрос 2] Найти самый длинный из массиванепрерывныйНисходящая подпоследовательность

Во-вторых, идеи решения проблем

[Вопрос 1] Используя идею динамического программирования, пусть dp [i] будет длиной убывающей подпоследовательности с i в качестве конечного элемента, тогда формула рекурсии:
dp[i] = max(dp[j]+1,dp[i]) (j<i && array[j]>array[i])

[Вопрос 2] Используйте два курсора начала и конца, чтобы записать начало и конец последовательно убывающих подпоследовательностей, и обновите значения начала и конца, как только они столкнутся с приращениями. Используйте max_len для записи длины самой длинной непрерывно убывающей подпоследовательности

В-третьих, алгоритм решения проблем

[Вопрос 1] Самый длинныйпрерывистыйУменьшающаяся подпоследовательность — динамическое программирование

/**************************************
author:tmw
date:2018-10-21
**************************************/
#include <stdio.h>
#include <stdlib.h>

#define max(a,b) (a>b?a:b)

/**
* @param int * заголовок массива в массив
 * @param int array_len длина массива
**/
int findMaxUncontinuesSubArray(int* array, int len)
{
    int* dp = (int*)malloc(len*sizeof(int));
    int i,j;
    for(i=0; i<len; i++)
    {
                 dp [i] = 1; // инициализация массива dp
        for(j=0; j<i; j++)
        {
            if(array[j]>array[i])
                                 dp [i] = max (dp [j] +1, dp [i]); // Включить массив [j] в последовательность с i в качестве конечного элемента
        }
    }
         // Находим самую длинную прерывистую убывающую подпоследовательность с i как конечный элемент
    int max_len = dp[0];
    for(i=1; i<len; i++)
    {
        if(max_len<dp[i])
            max_len = dp[i];
    }
    return max_len;
}

[Вопрос 2] Самый длинныйнепрерывныйУбывающая подпоследовательность

/**************************************
author:tmw
date:2018-10-21
**************************************/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define max(a,b) (a>b?a:b)
int findMaxContinueSubArray(int* array, int len)
{
    if(array==NULL || len<0) return -1;

    int start = 0;
    int end = 1;
    int max_len = INT_MIN;
    while(start<end && end<len)
    {
        while(array[end-1]>array[end] && end<len)
        {
            if(max_len<end-start+1)
            {
                printf("[%d-%d]n",start,end);
                max_len = end-start+1;
                printf("%dn",max_len);
            }
            end++;
        }
        if(array[end-1]<array[end])
        {
            start = end;
            end++;
        }
    }
    return max_len;
}

Мечты все еще нужны, если они сбываются ~~~ ヾ (◍ ° ∇ ° ◍) ノ ゙ ~~~~~~~~~~~~

Определение:
Последовательность (англ. sequence) — это набор элементов некоторого множества пронумерованный натуральными числами. Последовательность является результатом последовательного выбора элементов множества. При этом элементы последовательности могут повторяться. В частности, последовательность не является подмножеством заданного множества.

Содержание

  • 1 Виды последовательностей
  • 2 Теорема о связи длины НВП и НУП
  • 3 Следствие из теоремы
  • 4 См. также
  • 5 Источники информации

Виды последовательностей

Определение:
Последовательность элементов множества называется неубывающей (англ. nondecreasing), если каждый элемент этой последовательности не превосходит следующего за ним. — неубывающая .
Определение:
Последовательность элементов множества называется невозрастающей (англ. nonincreasing), если каждый следующий элемент этой последовательности не превосходит предыдущего. — невозрастающая .
Определение:
Последовательность элементов множества называется возрастающей (англ. increasing), если каждый следующий элемент этой последовательности превышает предыдущий. — возрастающая .
Определение:
Последовательность элементов множества называется убывающей (англ. decreasing), если каждый элемент этой последовательности превышает следующий за ним. — убывающая .
Определение:
Последовательность называется монотонной (англ. monotonic), если она является неубывающей, либо невозрастающей.
Определение:
Последовательность называется строго монотонной (англ. strictly monotonic), если она является возрастающей, либо убывающей.

Очевидно, что строго монотонная последовательность является монотонной.

Теорема о связи длины НВП и НУП

Теорема:

Пусть — перестановка чисел длины — длина наибольшей возрастающей подпоследовательности (НВП), — длина наибольшей убывающей подпоследовательности (НУП). Тогда .

Доказательство:

Рассмотрим два массива длины и , где — длина НВП, которая заканчивается на , — длина НУП, которая начинается на .

Докажем, что все пары различны.
Пусть существуют такие , что = и = . Если , тогда можно добавить к НВП, заканчивающейся на , следовательно . Если , то по аналогии . Противоречие! Следовательно все такие пары различны.

Заметим что , поэтому существуют различных пар . Если тогда среди пар найдутся две одинаковые. Такого быть не может по доказанному выше, т. е. , ч. т. д.

Следствие из теоремы

Утверждение:

Пусть — длина последовательности, тогда длина наибольшей монотонной подпоследовательности не меньше .

См. также

  • Задача о минимуме/максимуме скалярного произведения
  • Теорема Кэли
  • Матричное представление перестановок

Источники информации

  • Википедия — Последовательность
  • Wikipedia — Longest increasing subsequence

Подпоследовательности

Подпоследовательность
последовательности (xn) —
это последовательность
,
где (kn) — возрастающая
последовательность элементов множества
натуральных чисел.

Иными словами, подпоследовательность
получается из последовательности
удалением конечного или счётного числа
элементов.

Примеры

  • Последовательность простых
    чисел является подпоследовательностью
    последовательности натуральных чисел.

  • Последовательность натуральных чисел,
    кратных 12,
    является подпоследовательностью
    последовательности чётных
    натуральных чисел.

Свойства

  • Всякая последовательность является
    своей подпоследовательностью.

  • Для всякой подпоследовательности
    верно,
    что
    .

  • Подпоследовательность сходящейся
    последовательности сходится к тому же
    пределу, что и исходная последовательность.

  • Если все подпоследовательности некоторой
    исходной последовательности сходятся,
    то их пределы равны.

  • Любая подпоследовательность бесконечно
    большой последовательности также
    является бесконечно большой.

  • Из любой неограниченной числовой
    последовательности можно выделить
    бесконечно большую подпоследовательность,
    все элементы которой имеют определённый
    знак.

  • Из любой числовой последовательности
    можно выделить либо сходящуюся
    подпоследовательность, либо бесконечно
    большую подпоследовательность, все
    элементы которой имеют определённый
    знак.

Предельная точка последовательности

Основная статья: Предельная
точка

Предельная точка последовательности
— это точка, в любой окрестности которой
содержится бесконечно много элементов
этой последовательности. Для сходящихся
числовых последовательностей предельная
точка совпадает с пределом.

Предел последовательности

Основная статья: Предел
последовательности

Предел последовательности
это объект, к которому члены
последовательности приближаются с
ростом номера. Так в произвольном
топологическом
пространстве пределом последовательности
называется элемент, в любой окрестности
которого лежат все члены последовательности,
начиная с некоторого. В частности для
числовых последовательностей предел
— это число, в любой окрестности которого
лежат все члены последовательности
начиная с некоторого.

Частичный
предел последовательности
— это
предел одной из её подпоследовательностей.
У сходящихся числовых последовательностей
он всегда совпадает с обычным пределом.

Верхний предел последовательности
— это наибольшая предельная точка этой
последовательности.

Нижний предел последовательности
— это наименьшая предельная точка этой
последовательности.

Некоторые виды последовательностей

  • Стационарная последовательность
    — это последовательность, все члены
    которой, начиная с некоторого, равны.

(xn) стационарная

Ограниченные и неограниченные последовательности

В предположении о линейной
упорядоченности множества X
элементов последовательности можно
ввести понятия ограниченных и
неограниченных последовательностей.

  • Ограниченная сверху последовательность
    — это последовательность элементов
    множества X, все члены которой не
    превышают некоторого элемента из этого
    множества. Этот элемент называется
    верхней гранью данной
    последовательности.

(xn) ограниченная сверху

  • Ограниченная снизу последовательность
    — это последовательность элементов
    множества X, для которой в этом
    множестве найдётся элемент, не превышающий
    всех её членов. Этот элемент называется
    нижней гранью данной
    последовательности.

(xn) ограниченная снизу

  • Ограниченная последовательность
    (ограниченная с обеих сторон
    последовательность
    ) — это
    последовательность, ограниченная и
    сверху, и снизу.

(xn) ограниченная

  • Неограниченная последовательность —
    это последовательность, которая не
    является ограниченной.

(xn) неограниченная

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Понравилась статья? Поделить с друзьями:
  • Как найти скорость пешехода по графику
  • Как найти тангенс трех
  • Как найти ток утечки на ниве шевроле
  • Как найти сервер в тф2 по ip
  • Как найти абонента теле2 по номеру телефона