簡體   English   中英

給定序列,找到最大的“反向排序”子序列

[英]Given a sequence, find the largest 'reverse-ordered' subsequence

(是的,我盡可能多地搜索...)也許我不應該使用序列,但沒有更好的方法來描述它..

[修訂:如答案部分所述,子序列不是正確的描述。 一對數字是正確的詞!]

給定一系列數字並將序列中一對數字的大小定義為兩個數字之間的距離。 顯然最大的一對是[第一個數字,最后一個數字]。 問題是找到與[first,last]對相反的最大數字對。

例如,如果序列是{1,6,3,5,2,8}那么答案應該是[6,2]因為[1,8]的順序正在增加,而最大的順序是遞減順序是[6,2]。

一個附帶問題是,這可以使用SQL語句以聲明方式解決嗎? 具體來說,我正在考慮使用LINQ來做到這一點。

謝謝。

它不是適合SQL的那種問題。 它的措辭也很差。 你真的在尋找數字對而不是子序列,大小是兩者之間的距離。

可以通過向后掃描序列,在給定點之后的最小數量及其位置來解決O(n) 這給出了{1,2,2,2,2,8){0,4,4,4,4,5} 然后與原始序列並行掃描,得到{0,3,2,1,0,0}的大小,因此最大的大小是對(6,2) ,大小為3。

未經測試,但我會嘗試以下方法:

var sequence = new[] {1, 6, 3, 5, 2, 8};
var isGoingUp = sequence.First() < sequence.Last();

//if the first sequence is going up, invert the sign on the sequence
//this way we can always compare using "<"
var sequenceToCheck = sequence.Select(x => isGoingUp ? -x : x).ToList();

//initial values
int currentLength = 1; //the length of the subsequence found
int startIndex = 0; //the starting index of the subsequence

//check for each item's longest subsequence
for (int i = 0; i < sequenceToCheck.Count; i++)
{
    //go from the end towards the beginning and find the longest sequence for i
    for (int j = sequenceToCheck.Count - 1; i > j; i--)
    {
        if (sequenceToCheck[i] < sequenceToCheck[j])
        {
            //found i's longest subsequence
            if (currentLength < j - i + 1)
            {
                startIndex = i;
                currentLength = j - i + 1;
            }
            break; //don't check any smaller sequences for i
        }
    }

    if(sequenceToCheck.Count - i < currentLength)
        break; //no need to check any more, no sequence past this can be longer
}

var subsequence = sequence.Skip(startIndex).Take(currentLength);

您也應該能夠在LINQ中實現此解決方案,方法是計算從每個點到匹配數字的距離(從末尾開始)。


然而,在SQL中實現它會稍微困難一些,盡管你絕對可以做到這一點。 這是我的嘗試和一個有效的SQL小提琴示例

WITH firstValue AS (
    SELECT TOP 1 value
    FROM t
    ORDER BY id
), lastValue AS (
    SELECT TOP 1 value
    FROM t
    ORDER BY id DESC
), seqToCheck AS (
    SELECT id, 
        CASE WHEN lastValue.value > firstValue.value THEN 0-t.value 
             ELSE t.value 
        END AS value
    FROM t
    CROSS JOIN firstValue
    CROSS JOIN lastValue
), subSequences AS (
    SELECT s1.id, COALESCE(MAX(s2.id - s1.id + 1),1) AS distance
    FROM seqToCheck AS s1
    LEFT JOIN seqToCheck AS s2 ON s1.value < s2.value AND s2.id > s1.id
    GROUP BY s1.id
), longestSubSequence AS (
    SELECT TOP 1 id, distance
    FROM subSequences
    ORDER BY distance DESC
)
SELECT t.value
FROM t
INNER JOIN longestSubSequence AS l ON t.id >= l.id AND t.id < l.id + l.distance
ORDER BY t.id

這假設您具有不包含間隙的升序標識列id 如果你沒有這樣的東西,你也可以做ROW_NUMBER() OVER(ORDER BY xxxxx)

你可能會使它更復雜一些,以便使用索引。

一個好的算法是從外部進行比較,一旦得到你需要的東西,就會中斷。因為你的目標序列需要在第一個和最后一個之間進行比較,所以這個問題很容易實現。 從外部縮小序列可確保您更快地獲得所需的最大序列。

在你的情況下, {1,6,3,5,2,8}

1. Compare 1 and 8 
2. Compare 1 and 2
3. Compare 6 and 8
4. Compare 6 and 2 and you got your sequence

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM