Longest Increasing Subsequence(最长增长子数列)-LeetCode关于数组的思路和技巧

第一感受

又是一道不会特殊的数据结构和技巧,硬做出来结果超时的题目。
题目如下:

Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2) complexity.
Follow up: Could you improve it to O(n log n) time complexity?
Credits:
Special thanks to @pbrother for adding this problem and creating all test cases.
Subscribe to see which companies asked this question

问题如下:
1.使用循环进行遍历容器,当要在循环体中对容器中的元素进行增删改查,的结果是怎样的?(ConcurrentModificationException或者溢出的问题)

(1)使用iterator进行删除当前或者添加,iterator是动态更新的吗?
(2)使用for each 循环呢?使用get(index)呢?
(3)带有Tree字样的排序容器,你在遍历的过程中更改了排序的关键字会发生什么?
2.Comparable和Comparator的问题

Comparable 定义在 Person类的内部:
public class Persion implements Comparable {..比较Person的大小..},
因为已经实现了比较器,那么我们的Person现在是一个可以比较大小的对象了,它的比较功能和String完全一样,可以随时随地的拿来
比较大小,因为Person现在自身就是有大小之分的。Collections.sort(personList)可以得到正确的结果。
Comparator
Comparator 是定义在Person的外部的, 此时我们的Person类的结构不需要有任何变化,如
public class Person{ String name; int age },
然后我们另外定义一个比较器:
public PersonComparator implements Comparator() {..比较Person的大小..},

还有一个小问题就是定义Comparator的时候也要使用<>指定类型,否则就会要求使用类型转化来调用子类中的一些个函数。

Tag中有两个主要的问题
Dynamic Programming 和Binary Search
这两个算法没有考虑到会导致时间复杂度和空间复杂度很大。

Dynamic Programming

自己读了一下《算法导论》上面关于切割铁棒的动态规划的问题,在上网看了一下网友的其他解答。

DP指的是通过保留子问题的计算结果,在母问题运算的过程中直接使用子问题的结果。从而利用空间换取时间复杂度降低的trade off策略。

分为自顶向上和子地向下两种思虑。自顶向下使用递归的思虑,而自底向上不使用递归而是完全的从小到大解决所有的子问题。其系数相对于前者会少一些。

举个例子,铁棒问题中,给出10以内不同长度铁棒的价格表,从而求解不同长度原材料的铁棒采用什么切割方案可以获得最大的利润。
按照DP的思路,设总利润为rn,铁棒长度为n。
rn=max(rirni)
从而将铁棒切割问题分解为求解左边一段已知价格的铁棒,加上右边剩余铁棒的最大的利润。
从而将问题分解为一个树的结构,每一个子树对应一个子问题,每一个叶子节点对应最小子问题。保存从小到每一个叶子节点,大到每一个子问题,最终最终问题的计算结果。这样原问题方能得解。

回到这个题目

设给出的数组为nums,那么以nums[i]结尾的数组的子数列的长度,等于前nums[j] (j < i)元素中数值小于nums[i]的最大者加一。同时建立一个数组length存储以第i个元素为递增队列尾巴时候的队列长度。(等我学会公式编辑器的,汉语的力量我先发挥着)
遍历nums{
子遍历从0~i{
求得i之间的元素nums[j],满足
nums[i]< num[j],且length[j]为i之前元素中最大的。
则将length[i]+1;
}
}
如此得解。

相对于铁棒问题而言,这样的DP明显更加抽象。我们要善于从表象中发现规律。
最后附上我写了好久终于通过的代码:

public class Solution {
    public int lengthOfLIS(int[] nums) {
        final int n=nums.length;
        if(n==0)return 0;
        int[] max_length=new int [n];
        for(int i=0;i<n;i++){//initial to minum num 1;
            max_length[i]=1;
        }

        for(int i=1;i<n;i++){                
            int maxIndex=-1;                
            int max=-1;
            for(int j=i-1;j>=0;j--){
                if(nums[j]<nums[i]){
                    if(max_length[j]>=max){
                        maxIndex=j;
                        max=max_length[maxIndex];
                        System.out.println("i="+i+" "+"max ="+max+" maxIndex="+j);
                    }
                } 

            }

                if(maxIndex!=-1){
                     max_length[i]=max_length[maxIndex]+1;
                     System.out.println("max_length="+max_length[i]);
                }
        }
        int max=0;
        max=max_length[0];
        for(int i=0;i<n;i++){

            if(max_length[i]>max){
                max=max_length[i];
            }
        }
        return max;
    }
}

另外还用大神级别十分简洁的代码,希望通过上述的讲解你也能够看懂。

public class Solution {
    public int lengthOfLIS(int[] nums) {            
        int[] dp = new int[nums.length];
        int len = 0;

        for(int x : nums) {
            int i = Arrays.binarySearch(dp, 0, len, x);
            if(i < 0) i = -(i + 1);
            dp[i] = x;
            if(i == len) len++;
        }

        return len;
    }
}

你可能感兴趣的:(Longest Increasing Subsequence(最长增长子数列)-LeetCode关于数组的思路和技巧)