今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

字節跳動

首先,我們先來看一下字節跳動官網的招聘信息。在招聘首頁上寫著這麼一句話。“和優秀的人,做有挑戰的事”。

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

其次,我們可以看一下它招聘的研發職位要求,我這邊找了兩個,一個後臺研發,一個廣告算法兩個職位。在職位描述中,可以看到數據結構數據算法是必備項。

最後,就算不為了進入字節跳動,如果你抽一定的時間來學習算法,也可以加強自己的思維邏輯能力,對自己的技能提升也有非常大的幫助,會一門技術就多一條出路。

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?


字節跳動初面筆試算法題目-字符串反轉

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

方法一,JAVA語言特性

看到這樣的題目,首先我們應該想到使用最基礎的方法來解決這個問題。利用JAVA語言提供的特性,比如先通過String的split()方法拆分,然後集合工具類Collections.reverse()方法,最後再返回字符串。那如何實現呢?請看代碼;

<code>public static void main(String[] args) {
        String str="the sky is blue";
        //使用\\s+正則來以空格拆分字符串
        String[] strs = str.split("\\s+");
        //使用工具類Arrays.asList()將其轉換為List集合
        List strLists = Arrays.asList(strs);
        //使用Collections.reverse()方法反轉內容
        Collections.reverse(strLists);
        //使用StringJoiner來拼接反轉後的字符串即可
        str = String.join(" ", strLists);
       //打印str
        System.out.println(str);
    }/<code>

如果你沒有過算法學習,那麼你應該想到使用上訴的方法來解決這個問題。上述的代碼很簡單,使用的都是純工具類以及一些特定的API來解決這個。在上述代碼中可能會有一些朋友不清楚String.jion這個方法。因此我在這裡科普一下這個JDK1.8出的特性。

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

StringJoiner:通過JDK源碼我們可以發現,這個類有兩個構造器。五個公有方法。首先我們來看這兩個構造器,其實構造器一還是通過構造器二來實現的。因此我只以構造器二做講解。

<code>//構造器一
public StringJoiner(CharSequence delimiter) {
        this(delimiter, "", "");
    }
//構造器二
 public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {
        Objects.requireNonNull(prefix, "The prefix must not be null");
        Objects.requireNonNull(delimiter, "The delimiter must not be null");
        Objects.requireNonNull(suffix, "The suffix must not be null");
        // make defensive copies of arguments
        this.prefix = prefix.toString();
        this.delimiter = delimiter.toString();
        this.suffix = suffix.toString();
        this.emptyValue = this.prefix + this.suffix;
    }/<code>

StringJoiner構造器的三個參數,delimiter表示以什麼樣的方式來連接字符,比如上述代碼中,我使用的是“ ”來連接單詞字符。prefix,和suffix表示拼接後的字符串以什麼方式開始和結束。比如下面的例子,是不是非常簡單。

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

另外,在這個算法題中,我使用的是String.join()方法,其實join方法的底層實現也是使用的StringJoiner。我這邊貼上源碼,大家可以自己看一下,有興趣的朋友還可以研究一下StringJoiner的其它方法。

<code>public static String join(CharSequence delimiter,
            Iterable extends CharSequence> elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }/<code>

方法二,雙指針

雙指針的核心思想就是:一個指針負責循環遍歷,另一個指針負責條件處理

那針對於本題,如何用雙指針解法呢?請看下面源碼。我將原理以及解釋都放在代碼中,方便大家理解。只要大家記住一點,雙指針的特性即可,學會靈活使用雙指針,可以解決很多類似的算法題型。

<code>public static void main(String[] args) {
        String str="the sky is blue";
        //定義左右指針,右指針不動,左指針向左移動取單詞
        int right = str.length() - 1;
        int left = right;
        //存放反轉後的字符串
        StringBuilder res = new StringBuilder();
        while(left >= 0) {
            // 查找第一次出現的空格
            while(left >= 0 && str.charAt(left) != ' ') left--;
            //將單詞存放到res對象中
            res.append(str.substring(left + 1, right + 1) + " ");
            //跳動單詞之間的空格
            while(left >= 0 && str.charAt(left) == ' ') left--;
            // right 指向下個單詞的尾字符,左指針繼續前進
            right = left;
        }
        //去掉末尾的空格" "
        System.out.println(res.toString().trim());
    }/<code>
今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

方法三,雙端隊列實現

實現原理:因為雙端隊列可以支持從隊列頭部插入的方法,所以我們可以將字符串中的單詞一個一個進行處理,然後將每一個單詞push到隊列的頭部,再將隊列轉成字符串即可。原理圖如下所示

今日頭條筆試算法面試題,JAVA語言的三種實現方式,那一種最優?

實現代碼:

<code>public static void main(String[] args) {
        String str="the sky is blue";
        int left = 0;
        int right = str.length() - 1;
        //構建雙端隊列
        Deque deque = new ArrayDeque();
        StringBuilder word = new StringBuilder();
        while (left <= right) {
            char charStr = str.charAt(left);
            if ((word.length() != 0) && (charStr == ' ')) {
                // 將單詞 push 到隊列的頭部
                deque.offerFirst(word.toString());
                word.setLength(0);
            } else if (charStr != ' ') {
                word.append(charStr);
            }
            ++left;
        }
        deque.offerFirst(word.toString());
        System.out.println(String.join(" ", deque));
    }/<code>

其實,只要你明白了雙端隊列的原理以及特性,解決此類問題也非常簡單,當然本題還有很多種其它的解法。留個大家自行探索。

結語

像BAT這種互聯網大廠面試算法的本質就是看你的思路。當你的邏輯思維清楚,寫代碼也不過就幾分鐘的事情。因此,紮實的算法基礎和紮實的語言基礎很重要,因為算法只是解決問題的手段,需要的是從眾多算法中找出最優算法的能力。


分享到:


相關文章: