算法-一個經典sql 題和一個Java算法題

1.sql題描述

話說有一個日誌表,只有兩列,分別是連續id和num 至於啥意思,把它當金額把。如今想知道連續次數3次及以上的num,數據以下sql

id num
1 1
2 1
3 1
4 2
5 3
6 4
7 4
8 4

那麼結果只有1,4知足條件,問這個sql該怎麼寫?數組

2.思路和解法

分析:題目簡單,沒有歧義,能看得懂,像連續幾回的這種問題必定是用到窗口函數,首先想到的是排名row_number 而後lag 怎麼體現連續呢,確定是須要用到一個排序的id,因爲題目給了id是連續遞增的,能夠省去row_number了函數

因此第一步,上lag,結果就是以下:大數據

id num lagid
1 1 null
2 1 0
3 1 0
4 2 1
5 3 1
6 4 1
7 4 0
8 4 0

獲得lagid後,連續怎麼用呢,首先只有爲0的才知足條件,因此能夠作一個篩選,結果就以下表去掉xxx的,下面觀察0的行,怎麼區分3 行的 0 和 7行的 0呢,想到使用新分組,rid 這樣就把lagid 相同,num相同的排序,最後再加一列,id-rid 相同的分爲一組日誌

id num lagid rid gid
1 1 null xxx
2 1 0 1 1
3 1 0 2 1
4 2 1 xxx
5 3 1 xxx
6 4 1 xxx
7 4 0 1 6
8 4 0 2 6
-- 完整sql
## 解法1
SELECT num
FROM
  (SELECT id,
          num,
          lagid,
          (id-row_number() over(PARTITION BY num, lagid
                                ORDER BY id)) AS gid
   FROM
     (SELECT id,
             num,
             num- lag(num) (OVER PARTITION BY 1
                            ORDER BY id) AS lagid) tmp1
   WHERE lagid=0 ) tmp2
GROUP BY num,
         gid
HAVING count(*) >= 2


## 解法2  
select
  num,
  gid,
  count(1) as c
from
(
select
id,
num,
id-row_number() over(PARTITION BY num ORDER BY id) as gid
from 
(select * from logs order by num,id) a
) b
group by num,gid

後面想到了更好的,其實不用lag,也不用order by 全局排序,id 的做用和日期同樣,通常是用來配合row_number來解決連續問題的,因此row_number必不可少,那麼能夠這樣寫(神他媽簡單是否是,別想複雜了):code

SELECT num,
       gid
FROM
  (SELECT num,
          id-row_number() OVER (PARTITION BY num
                                ORDER BY id) gid
   FROM logs)
GROUP BY num,
         gid
HAVING count(1) >= 3

3. Java題描述

首先,給你一個初始數組 arr。而後,天天你都要根據前一天的數組生成一個新的數組。第 i 天所生成的數組,是由你對第 i-1 天的數組進行以下操做所得的:假如一個元素小於它的左右鄰居,那麼該元素自增 1。假如一個元素大於它的左右鄰居,那麼該元素自減 1。排序

首、尾元素 永不 改變。開發

過些時日,你會發現數組將會再也不發生變化,請返回最終所獲得的數組。get

示例 1:input

輸入:[6,2,3,4]

輸出:[6,3,3,4]

解釋:

第一天,數組從 [6,2,3,4] 變爲 [6,3,3,4]。

沒法再對該數組進行更多操做。

示例 2:

輸入:[1,6,3,4,3,5]

輸出:[1,4,4,4,4,5]

解釋:

第一天,數組從 [1,6,3,4,3,5] 變爲 [1,5,4,3,4,5]。

次日,數組從 [1,5,4,3,4,5] 變爲 [1,4,4,4,4,5]。

沒法再對該數組進行更多操做。

3.3 分析和解法

  1. 首先考慮一輪遍歷怎麼寫,應該很簡單把,思路就是一個大小爲3的窗口

  2. 用一個flag來標誌每一輪是否有改過數據。那麼代碼以下:

public int[] get(int[] input) {
    if (input == null || input.length <=2)
        return input;
    boolean flag = false;
        do {
            flag = false;
            for (int i=1;i+1 < input.length;i++){
                if (input[i] < input[i+1] && input[i] < input[i-1] ) {
                    input[i] +=1;
                    if (!flag)
                        flag = true;
                }
                if (input[i] > input[i+1] && input[i] > input[i-1] ) {
                    input[i] -=1;
                    if (!flag)
                        flag = true;
                    }
            }
        } while(flag)
        return input;
}

大數據開發,更多關注查看我的資料

相關文章
相關標籤/搜索