• 动态规划之最长公共子序列/最长公共子串


    最长公共子序例 和最长公共子串

    最长公共子序例 与最长公共子串 的区别  子串要求在原字符串中是连续的,而子序列则只需保持相对顺序一致,并不要求连续。例如X = {a, Q, 1, 1}; Y = {a, 1, 1, d, f}那么,{a, 1, 1}是X和Y的最长公共子序列,但不是它们的最长公共字串。

    一、最长公共子序例

    只求最长子序例长度

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int arr[499][499];
    int main() {
      string str, str1;
      while (cin>>str>>str1) {
        memset(arr, 0, sizeof(arr));
           int k = str.size();
           int l = str1.size();
           int count = 0;
           for (int i = 0; i < k; i++) {
               for (int j = 0; j < l; j++) {
                   if (str[i] == str1[j]) {
                      arr[i+1][j+1] = arr[i][j] + 1;            
                    }else {
                      arr[i+1][j+1] = max(arr[i+1][j],arr[i][j+1]);
                    }
                }
            }
            cout<<arr[k][l]<<endl;
      } 
    }

    二、最长公共子串

     最长公共子串与最长公共子序例的不同是str[i] != str1[j] 的时候  arr[i][j] = 0 而不是 arr[i][j] = max(arr[i-1][j],arr[i][j-1]);

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int arr[499][499];
    int main() {
      string str, str1;
      while (cin>>str>>str1) {
        memset(arr, 0, sizeof(arr));
           int k = str.size();
           int l = str1.size();
           int maxsum = 0;
           for (int i = 0; i < k; i++) {
               for (int j = 0; j < l; j++) {
                   if (str[i] == str1[j]) {
                     arr[i+1][j+1] = arr[i][j] + 1;
                     if (maxsum < arr[i+1][j+1])
                        maxsum = arr[i+1][j+1]            
                    }else {
                      arr[i+1][j+1] = 0;
            }
                }
            }
            cout<<maxsum<<endl;
      } 
    }

    三、最长递增子序例

    设长度为N的数组为{a0,a1, a2, ...an-1),则假定以aj结尾的数组序列的最长递增子序列长度为L(j),则L(j)={ max(L(i))+1, i<j且a[i]<a[j] }。也就是说,我们需要遍历在j之前的所有位置i(从0到j-1),找出满足条件a[i]<a[j]的L(i),求出max(L(i))+1即为L(j)的值。最后,我们遍历所有的L(j)(从0到N-1),找出最大值即为最大递增子序列。时间复杂度为O(N^2)。

    /*
    有毒数组开到100超时开1000超内存 
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int arr[100000];
    int a[100000];
    int main() {
      int n; 
      while (scanf("%d", &n) != EOF) {
         memset(arr, 0, sizeof(arr));
         for (int i = 0; i < n; i++) scanf("%d", &a[i]);
         int max = 0;
         for (int i = 1; i < n; i++) {
           for (int j = 0; j < i; j++) {
               if (a[j] < a[i] && arr[j] + 1 > arr[i]) {
                  arr[i] = arr[j] + 1;
                  if (arr[i] > max) max = arr[i];        
               }
           }
          }
        printf("%d
    ", max+1);
        } 
    }

    最长递增子序例解法二

       二分法

    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
      
    #define N 9 //数组元素个数  
    int array[N] = {2, 1, 6, 3, 5, 4, 8, 7, 9}; //原数组  
    int B[N]; //在动态规划中使用的数组,用于记录中间结果,其含义三言两语说不清,请参见博文的解释  
    int len; //用于标示B数组中的元素个数  
      
    int LIS(int *array, int n); //计算最长递增子序列的长度,计算B数组的元素,array[]循环完一遍后,B的长度len即为所求  
    int BiSearch(int *b, int len, int w); //做了修改的二分搜索算法  
      
    int main()  
    {  
        printf("LIS: %d
    ", LIS(array, N));  
      
        int i;  
        for(i=0; i<len; ++i)  
        {  
            printf("B[%d]=%d
    ", i, B[i]);  
        }  
      
        return 0;  
    }  
      
    int LIS(int *array, int n)  
    {  
        len = 1;  
        B[0] = array[0];  
        int i, pos = 0;  
      
        for(i=1; i<n; ++i)  
        {  
            if(array[i] > B[len-1]) //如果大于B中最大的元素,则直接插入到B数组末尾  
            {  
                B[len] = array[i];  
                ++len;  
            }  
            else  
            {  
                pos = BiSearch(B, len, array[i]); //二分查找需要插入的位置  
                B[pos] = array[i];  
            }  
        }  
      
        return len;  
    }  
      
    //修改的二分查找算法,返回数组元素需要插入的位置。  
    int BiSearch(int *b, int len, int w)  
    {  
        int left = 0, right = len - 1;  
        int mid;  
        while (left <= right)  
        {  
            mid = left + (right-left)/2;  
            if (b[mid] > w)  
                right = mid - 1;  
            else if (b[mid] < w)  
                left = mid + 1;  
            else    //找到了该元素,则直接返回  
                return mid;  
        }  
        return left;//数组b中不存在该元素,则返回该元素应该插入的位置  
    }  

    四’最大子串和

    void solve() {
      int sum = 0;
      int max = -0xfff;
      for (int i = 0; i < n; i++) {
        sum += arr[i];
        if (sum > max) {
          max = sum;
        }else if (sum < 0) {
          sum = 0;
        }
      }
    } 
  • 相关阅读:
    20、插入横向文本框,输入文字后,文字周围有留白
    46、文字工具
    19、表格—单元格输入文字后,四周留白边
    50、路径选择工具
    48、钢笔工具【P】—形状
    49、路径和形状
    leetcode 235. Lowest Common Ancestor of a Binary Search Tree 二叉搜索树的最近公共祖先(简单)
    leetcode 226. Invert Binary Tree 翻转二叉树(简单)
    leetcode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树) (中等)
    leetcode 144. Binary Tree Preorder Traversal 二叉树展开为链表(中等)
  • 原文地址:https://www.cnblogs.com/a863886199/p/7822047.html
Copyright © 2020-2023  润新知