benym的知识笔记 benym的知识笔记
🦮首页
  • Java

    • Java-基础
    • Java-集合
    • Java-多线程与并发
    • Java-JVM
    • Java-IO
  • Python

    • Python-基础
    • Python-机器学习
  • Kafka
  • Redis
  • MySQL
  • 分布式事务
  • Spring

    • SpringIOC
    • SpringAOP
🦌设计模式
  • 剑指Offer
  • LeetCode
  • 排序算法
🐧实践
  • Rpamis

    • Utils
    • Exception
    • Security
  • 归档
  • 标签
  • 目录
🦉里程碑
🐷关于
GitHub (opens new window)

benym

惟其艰难,才更显勇毅🍂惟其笃行,才弥足珍贵
🦮首页
  • Java

    • Java-基础
    • Java-集合
    • Java-多线程与并发
    • Java-JVM
    • Java-IO
  • Python

    • Python-基础
    • Python-机器学习
  • Kafka
  • Redis
  • MySQL
  • 分布式事务
  • Spring

    • SpringIOC
    • SpringAOP
🦌设计模式
  • 剑指Offer
  • LeetCode
  • 排序算法
🐧实践
  • Rpamis

    • Utils
    • Exception
    • Security
  • 归档
  • 标签
  • 目录
🦉里程碑
🐷关于
GitHub (opens new window)
  • 剑指Offer

    • 01背包问题详解
    • LeetCode-面试题17-打印从1到最大的n位数
    • LeetCode-面试题03-不修改数组找出重复的数字
    • LeetCode-面试题03-数组中重复的数字
    • LeetCode-面试题04-二维数组中的查找
    • LeetCode-面试题05-替换空格
    • LeetCode-面试题06-从尾到头打印链表
    • LeetCode-面试题09-用两个栈实现队列
    • LeetCode-面试题10-1-斐波那契数列
    • LeetCode-面试题10-2-青蛙跳台阶
    • LeetCode-面试题11-旋转数组的最小数字
    • LeetCode-面试题13-机器人的运动范围
    • LeetCode-面试题14-1-剪绳子
    • LeetCode-面试题14-2-剪绳子(大数)
    • LeetCode-面试题15-二进制中1的个数
    • LeetCode-面试题16-数值的整数次方
    • LeetCode-面试题18-删除链表的节点
    • LeetCode-面试题19-正则表达式匹配
    • LeetCode-面试题20-表示数值的字符串
    • LeetCode-面试题21-调整数组顺序使奇数位于偶数前面
    • LeetCode-面试题22-链表中倒数第k个节点
    • LeetCode-面试题24-反转链表
    • LeetCode-面试题25-合并两个排序的链表
    • LeetCode-面试题26-树的子结构
    • LeetCode-面试题27-二叉树的镜像
    • LeetCode-面试题29-顺时针打印矩阵
    • LeetCode-面试题31-栈的压入弹出序列
    • LeetCode-面试题32-1-从上到下打印二叉树
    • LeetCode-面试题32-2-从上到下打印二叉树
    • LeetCode-面试题32-3-从上到下打印二叉树
    • LeetCode-面试题35-复杂链表的复制
    • LeetCode-面试题36-二叉搜索树与双向链表
    • LeetCode-面试题37-序列化二叉树
    • LeetCode-面试题38-字符串的排列
    • LeetCode-面试题39-数组中出现次数超过一半的数字
    • LeetCode-面试题40-最小的k个数
    • LeetCode-面试题41-数据流中的中位数
    • LeetCode-面试题42-连续子数组的最大和
    • LeetCode-面试题43-1到n整数中1出现的次数
    • LeetCode-面试题44-数字序列中某一位的数字
    • LeetCode-面试题45-把数组排成最小的数
    • LeetCode-面试题47-礼物的最大价值
    • LeetCode-面试题48-最长不含重复字符的子字符串
    • LeetCode-面试题49-丑数
    • LeetCode-面试题50-第一次只出现一次的字符
    • LeetCode-面试题51-数组中的逆序对
    • LeetCode-面试题53-1-在排序数组中查找数字I
    • LeetCode-面试题33-二叉搜索树的后序遍历序列
    • LeetCode-面试题54-二叉搜索树的第k大节点
    • LeetCode-面试题55-1-二叉树的深度
    • LeetCode-面试题12-矩阵中的路径
    • LeetCode-面试题30-包含min函数的栈
    • LeetCode-面试题34-二叉树中和为某一值的路径
    • LeetCode-面试题46-把数字翻译成字符串
    • LeetCode-面试题55-2-平衡二叉树
    • LeetCode-面试题56-1-数组中数字出现的次数
    • LeetCode-面试题56-2-数组中数字出现的次数2
    • LeetCode-面试题57-和为s的两个数字
    • LeetCode-面试题58-1-翻转单词顺序
    • LeetCode-面试题58-2-左旋转字符串
    • LeetCode-面试题59-2-队列的最大值
    • LeetCode-面试题60-n个骰子的点数
    • LeetCode-面试题61-扑克牌中的顺子
    • LeetCode-面试题62-圆圈中最后剩下的数字
    • LeetCode-面试题63-股票的最大利润
    • LeetCode-面试题64-求1+2+到+n
    • LeetCode-面试题65-不用加减乘除做加法
    • LeetCode-面试题66-构建乘积数组
    • LeetCode-面试题67-把字符串转化成整数
    • LeetCode-面试题68-1-二叉搜索树的最近公共祖先
    • LeetCode-面试题68-2-二叉搜索树的最近公共祖先
    • LeetCode-面试题07-重建二叉树
    • LeetCode-面试题52-两个链表的第一个公共节点
    • LeetCode-面试题53-2-0到n-1中缺失的数字
    • LeetCode-面试题57-2-和为s的连续正数序列
    • LeetCode-面试题59-1-滑动窗口的最大值
    • LeetCode-面试题28-对称的二叉树
  • LeetCode

    • LeetCode-54-螺旋矩阵
    • LeetCode-67-二进制求和
    • LeetCode-83-删除排序链表中的重复元素
    • LeetCode-415-字符串相加
    • LeetCode-498-对角线遍历
    • LeetCode-724-寻找数组的中心索引
    • 动态规划问题——最长上升子序列(LIS)(一)
    • 动态规划问题——最长上升子序列(LIS)(二)
    • 动态规划问题——最长上升子序列(LIS)(三)
      • LeetCode-144-二叉树的前序遍历
      • LeetCode-94-二叉树的中序遍历
      • LeetCode-145-二叉树的后序遍历
      • LeetCode-53-最大子序和
      • LeetCode-392-判断子序列
      • LeetCode-303-区域和检索-数组不可变
      • LeetCode-2-两数相加
      • LeetCode-3-无重复字符的最长字串
      • LeetCode-4-寻找两个正序数组的中位数
      • LeetCode-5-最长回文字串
      • LeetCode-11-盛最多水的容器
      • LeetCode-15-三数之和
      • LeetCode-17-电话号码的字母组合
      • LeetCode-19-删除链表的倒数第N个节点
      • LeetCode-20-有效的括号
      • LeetCode-21-合并两个有序链表
      • LeetCode-22-括号生成
      • LeetCode-23-合并K个排序链表
      • LeetCode-31-下一个排列
      • LeetCode-32-最长有效括号
      • LeetCode-33-搜索旋转排序数组
      • LeetCode-34-在排序数组中查找元素的第一个和最后一个位置
      • LeetCode-39-组合总数
      • LeetCode-46-全排列
      • LeetCode-47-全排列2
      • LeetCode-51-N皇后
      • LeetCode-55-跳跃游戏
      • LeetCode-56-合并区间
      • LeetCode-62-不同路径
      • LeetCode-64-最小路径和
      • LeetCode-70-爬楼梯
      • LeetCode-72-编辑距离
      • LeetCode-75-颜色分类
      • LeetCode-76-最小覆盖字串
      • LeetCode-77-组合
      • LeetCode-78-子集
      • LeetCode-84-柱状图中最大的矩形
      • LeetCode-102-二叉树的层序遍历
      • LeetCode-104-二叉树的最大深度
      • LeetCode-105-从前序与中序遍历构造二叉树
      • LeetCode-107-二叉树的层次遍历2
      • LeetCode-114-二叉树展开为链表
      • LeetCode-121-买卖股票的最佳时机
      • LeetCode-128-最长连续序列
      • LeetCode-136-只出现一次的数字
      • LeetCode-142-环形链表2
      • LeetCode-143-重排链表
      • LeetCode-146-LRU缓存机制
      • LeetCode-152-乘积最大子数组
      • LeetCode-198-打家劫舍
      • LeetCode-199-二叉树的右视图
      • LeetCode-206-反转链表
      • LeetCode-207-课程表
      • LeetCode-215-数组中的第K个最大元素
      • LeetCode-221-最大正方形
      • LeetCode-226-翻转二叉树
      • LeetCode-236-二叉树的最近公共祖先
      • LeetCode-279-完全平方数
      • LeetCode-287-寻找重复数
      • LeetCode-300-最长上升子序列
      • LeetCode-309-最佳买卖股票时机含冷冻期
      • LeetCode-322-零钱兑换
      • LeetCode-328-奇偶链表
      • LeetCode-347-前K个高频元素
      • LeetCode-394-字符串解码
      • LeetCode-406-根据身高重建队列
      • LeetCode-413-等差数列划分
      • LeetCode-416-分割等和子集
      • LeetCode-438-找到字符串中所有字母异位词
      • LeetCode-448-找到所有数组中消失的数字
      • LeetCode-461-汉明距离
      • LeetCode-494-目标和
      • LeetCode-538-把二叉搜索树转换为累加树
      • LeetCode-543-二叉树的直径
      • LeetCode-560-和为K的子数组
      • LeetCode-567-字符串的排列
      • LeetCode-581-最短无序连续子数组
      • LeetCode-617-合并二叉树
      • LeetCode-704-二分查找
      • LeetCode-739-每日温度
      • LeetCode-747-至少是其他数字两倍的最大数
      • LeetCode-890-查找和替换模式
      • LeetCode-1143-最长公共子序列
      • LeetCode-1247-交换字符使得字符串相同
      • LeetCode-1367-二叉树中的列表
      • LeetCode-字符串排序
      • LeetCode-面试题02.02-返回倒数第k个节点
      • LeetCode-面试题17.16-按摩师
      • 获取满足指数的最长字符串
      • 数组的最多素数个数
      • 最小字典序字符串
      • LeetCode-1-两数之和
      • LeetCode-16-最接近的三数之和
      • LeetCode-679-24点游戏
      • LeetCode-141-环形链表
      • LeetCode-155-最小栈
      • LeetCode-160-相交链表
      • 判断一棵二叉树是否为二叉搜索树和完全二叉树
      • LeetCode-169-多数元素
      • LeetCode-234-回文链表
      • LeetCode-238-除自身以外数组的乘积
      • LeetCode-283-移动零
      • LeetCode-338-比特位计数
      • LeetCode-797-所有可能的路径
    • 排序算法

      • 常见排序算法总结
      • 冒泡排序
      • 基数排序
      • 堆排序
      • 希尔排序
      • 归并排序
      • 快速排序
      • 插入排序
      • 桶排序
      • 选择排序
    • 算法
    • LeetCode
    benym
    2018-08-26
    目录

    动态规划问题——最长上升子序列(LIS)(三)

    样本代码时间复杂度为〇(nlogn),笔试题

    上一个版本用二分法优化了时间复杂度,但其实根据数据的样本观察可知,后面的数据都是重复的,我们只需要当列表遍历到一小时数据的最后时将后面数据的最大数加入到列表即可,这样可以快速跳出循环,避免后面不必要的查找

    以下代码略有区别,一种是计算数目,一种是使用新列表存储,但大致思路类似。

    写完之后发现可以考虑的情况还是有的,还可以继续优化,不过优化到这里应该也差不多了,列表的append方法性能上是非常好的。两个版本Java耗时0.000196s,Python耗时0.000050s

    # Java代码

    import java.util.*;
    
    public class Main {
        public static void main(String[] args) {
            Scanner scan = new Scanner(System.in);
            while (true) {
                int k = scan.nextInt();
                int t = scan.nextInt();
                int[] arr = new int[k];
                for (int i = 0; i < arr.length; ++i)
                    arr[i] = scan.nextInt();
                System.out.println(new Main().lengthOfLIS(arr, t));
            }
        }
        
        public int lengthOfLIS(int[] nums, int count) {
    
            int[] dp = new int[nums.length];
            dp[0] = -1;
            // 获取nums数组里面的最大数字
            int[] maxCount = getMaxCount(nums);
            int maxLen = 0, t = 1;
            boolean flag = true;
            for (; t <= count; t++) {
                int count2 = 0;
                if (flag) {
                    for (int i = 0; i < nums.length; i++) {
                        if (maxLen == 0) {
                            dp[maxLen++] = nums[i];
                        } else {
                            if (nums[i] >= dp[maxLen - 1]) {
                                if (nums[i] == maxCount[0])
                                    count2++;
                                dp[maxLen++] = nums[i];
                                if (maxLen - 1 == nums.length - 1) {
                                    flag = false;
                                    maxLen += maxCount[1] - count2;
                                    break;
                                }
                            } else {
                                int index = binarySearch(dp, maxLen - 1, nums[i]);
                                dp[index] = nums[i];
                            }
                        }
                    }
                    if (!flag)
                        break;
                }
            }
            return maxLen + (count - t) * maxCount[1];
        }
    
        public int binarySearch(int[] dp, int len, int target) {
            int start = 0, end = len - 1;
            while (start <= end) {
                int mid = (start + end) / 2;
                if (dp[mid] > target)
                    end = mid - 1;
                else if (dp[mid] > target)
                    start = mid + 1;
                else
                    return mid;
            }
            return start;
        }
    
        public int[] getMaxCount(int[] nums) {
    
            int max = Integer.MIN_VALUE, count = 0;
            for (int i = 0; i < nums.length; i++)
                max = Math.max(max, nums[i]);
            for (int i = 0; i < nums.length; i++) {
                if (max == nums[i])
                    count++;
            }
            return new int[]{max, count};
        }
    }
    
    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
    74
    75
    76
    77
    78
    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
    74
    75
    76
    77
    78

    # Python代码

    def longestIncreasingSubsequence(nums, n, m):
        if nums == None or len(nums) == 0:
            return 0
        testarray = list()
        maxNum = max(nums)
        minNum = min(nums)
        count = 0
        for i in range(len(nums)):
            if i == n:
                for j in range(m - 1):
                    testarray.append(maxNum)
                break
            # 如果是第一个位置就直接添加进新的列表里面,如果后一个元素比新列表的最后一个元素大或者等于,则添加该元素到新列表末尾
            if len(testarray) == 0 or nums[i] >= testarray[len(testarray) - 1]:
                testarray.append(nums[i])
            # 这一行的目的是保证新列表中的数据全部都是顺序递增的,不让后面的小的数据插入到前面,防止数列个数对了,但是实际上数据不是正序的情况
            # 1、如果是一小时采样点的最后一个,比如8 6 7 4,  4就是一小时中最后一个采样点,而且这个数是最小值,就跳过本次循环
            # 2、如果是一小时采样点的最后一个,比如10 3 7 5, 5就是一小时中最后一个采样点,而且这个数比之前数列的最后一个值小,就跳过本次循环
            elif nums[i] == minNum and (i % (n - 1) == 0) or nums[i] < testarray[len(testarray) - 1] and (i % (n - 1) == 0):
                continue
            else:
                # 如果这个新元素不大于等于最后一个元素的时候,利用二分查找找到他在新列表中应该插入的位置
                index = findFirstLargeEqual(testarray, nums[i])
                # 将新元素替换对应位置的列表里面的元素
                testarray[index] = nums[i]
        return len(testarray)
    
    
    # 利用二分查找法
    def findFirstLargeEqual(testarray, target):
        left = 0
        right = len(testarray) - 1
        if testarray[0] == target:
            return 0
        while left <= right:
            # 双斜杠整除
            mid = (left + right) // 2
            if testarray[mid] > target:
                right = mid - 1
            elif testarray[mid] < target:
                left = mid + 1
            else:
                return mid
        return left
    
    
    if __name__ == "__main__":
        a = list()
        # 输入n m
        n, m = input().split()
        # 输入采样点
        n = int(n)
        a = input().split()
        # 截取输入的前n个(控制输入)
        a = a[:n]
        # 全部转化为整形
        for i in range(n):
            a[i] = int(a[i])
        # 按照小时数重复
        a = a * int(m)
        count = longestIncreasingSubsequence(a, n, int(m))
        print(count)
    
    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
    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

    # 运行结果

    5 10
    5 6 7 9 1
    13
    
    1
    2
    3
    1
    2
    3
    编辑 (opens new window)
    #算法#Java#Python#DP
    上次更新: 2022/11/18, 11:15:10
    动态规划问题——最长上升子序列(LIS)(二)
    LeetCode-144-二叉树的前序遍历

    ← 动态规划问题——最长上升子序列(LIS)(二) LeetCode-144-二叉树的前序遍历→

    最近更新
    01
    SpringCache基本配置类
    05-16
    02
    DSTransactional与Transactional事务混用死锁场景分析
    03-04
    03
    Rpamis-security-原理解析
    12-13
    更多文章>
    Theme by Vdoing | Copyright © 2018-2024 benym | MIT License
     |   |   | 
    渝ICP备18012574号 | 渝公网安备50010902502537号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式