常見的面試編程題--鏈表+樹

通過遞歸實(shí)現(xiàn)創(chuàng)建一個(gè)鏈表

Node節(jié)點(diǎn)的定義

public class Node {
    private final int value;
    private Node next ;
    public Node(int value)
    {
        this.value = value;
        next = null;
    }

    public int getValue() {
        return value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    public static void printLinkedList(Node node)
    {
        while (node!=null)
        {
            System.out.print(node.getValue());
            System.out.print(" ");
            node = node.getNext();

        }
        System.out.println();

    }
}

遞歸創(chuàng)建鏈表

public Node createLinkedList(List<Integer> data)
    {
        if (data.isEmpty())
        {
            return  null;
        }
        Node firstNode = new Node(data.get(0));
        firstNode.setNext(createLinkedList(data.subList(1,data.size())));
        return firstNode;
    }

給定value值刪除鏈表中出現(xiàn)的所有節(jié)點(diǎn)兴使,存在多個(gè)相同節(jié)點(diǎn)的情況。

注意點(diǎn):

  • 頭節(jié)點(diǎn)就出現(xiàn)匹配的數(shù)據(jù)照激,而且不止一個(gè)
  • 刪除節(jié)點(diǎn)的思想:改變next的指向
  • 找出共同處理的地方使用循環(huán)的思想解決
    public Node deleteIfValue(Node head,int value){

        //特殊情況发魄,頭節(jié)點(diǎn)存在匹配value的情況
        while (head!=null&&head.getValue()==value)
        {
            head = head.getNext();
        }
        if (head==null)
        {
            return null;
        }
        //定義出一個(gè)指針
        Node pre = head;
        while (pre.getNext()!=null)
        {
            if (pre.getNext().getValue()==value)
            {
                pre.setNext(pre.getNext().getNext());
            }else {
                pre = pre.getNext();
            }
        }
        return head;
    }

利用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的操作

棧的存儲(chǔ)特點(diǎn)是后進(jìn)先出,所以兩個(gè)棧一個(gè)作為壓棧使用俩垃,另一個(gè)作為彈出励幼,但是要注意的一點(diǎn)就是需要保證棧1的元素都完全倒入到棧2中。

兩個(gè)各司其職的棧
  • 如果stackPush要往stackPop中壓入數(shù)據(jù)口柳,那么久必須把stackPush中的元素全部壓入苹粟。
  • 如果stackPop中不為空,那么就不可以往stackPop壓入元素跃闹。
public class StackQueue {

    public Stack<Integer>   stackPush;
    public Stack<Integer>   stackPop;

    public StackQueue()
    {
        stackPush = new Stack<Integer>();
        stackPop = new Stack<Integer>();
    }

    //隊(duì)列進(jìn)隊(duì)
    public void add(Integer i)
    {
        stackPush.push(i);
    }

    //隊(duì)列的poll方法
    public int poll()
    {
        if (stackPop.empty()&&stackPush.empty())
        {
            System.out.println("隊(duì)列為空嵌削。");
        }
        else if (stackPop.empty())
        {
            while (!stackPush.empty())
            {
                stackPop.push(stackPush.pop());
            }

        }
        return  stackPop.pop();

    }

    //隊(duì)列的peek方法
    public int peek()
    {
        if (stackPop.empty()&&stackPush.empty())
        {
            System.out.println("隊(duì)列為空毛好。");
        }else if (stackPop.empty())
        {
            while (!stackPush.empty())
            {
                stackPop.push(stackPush.pop());
            }
        }
        return stackPop.peek();
    }
}

判斷一個(gè)鏈表是不是回文的結(jié)構(gòu)

題目:給定一個(gè)鏈表的頭結(jié)點(diǎn)head,請判斷該鏈表是不是回文的結(jié)構(gòu)苛秕?
解決思路:利用棧的存儲(chǔ)后進(jìn)先出的特點(diǎn)進(jìn)行回文的判定

//鏈表節(jié)點(diǎn)的定義
class LinkedNode
{
    int value;
    LinkedNode next = null;
    LinkedNode(int value)
    {
        this.value = value;
    }
}
    public boolean isPalindrome(LinkedNode head)
    {
        if (head==null){
            return  false;
        }
        Stack<Integer> stack = new Stack<Integer>();
        LinkedNode cur = head;
        //將鏈表的數(shù)據(jù)壓入棧中
        while (cur!=null)
        {
           stack.push(cur.value);
           cur = cur.next;
        }

        //出棧進(jìn)行回文判斷
        while (head!=null)
        {
            if (head.value!=stack.pop())
            {
                return false;
            }
            head = head.next;
        }

        return true;
    }

刪除一個(gè)鏈表中重復(fù)出現(xiàn)的節(jié)點(diǎn)

題目: 給定一個(gè)無序單鏈表的頭節(jié)點(diǎn)head肌访,刪除其中值重復(fù)出現(xiàn)的節(jié)點(diǎn)。
例如:1->2->3->3->4->4->2->1->1->null艇劫,刪除值重復(fù)的節(jié)點(diǎn)之后為
1->2->3->4->2->1->null

解決思路:

  • 生成一個(gè)哈希表吼驶,因?yàn)轭^節(jié)點(diǎn)是不用刪除的節(jié)點(diǎn),所以首先將頭節(jié)點(diǎn)的值存放入哈希表
  • 從頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)開始往后遍歷節(jié)點(diǎn)港准,假設(shè)當(dāng)前遍歷到cur節(jié)點(diǎn)旨剥,先檢查cur的值是否在哈希表中,如果在浅缸,則說明cur節(jié)點(diǎn)的值是之前出現(xiàn)過的轨帜,就將cur節(jié)點(diǎn)刪除,刪除的方式是將最近一個(gè)沒有被刪除的節(jié)點(diǎn)pre連接到cur的下一個(gè)節(jié)點(diǎn)衩椒,即pre.next = cur.next.如果不在蚌父,將cur節(jié)點(diǎn)的值加入哈希表,同時(shí)令pre=cur毛萌,即更新最近一個(gè)沒有被刪除的節(jié)點(diǎn)苟弛。
    public void DeleteListNode(LinkedNode head)
    {
        //如果頭結(jié)點(diǎn)是空的話結(jié)束程序
        if (head==null)
        {
            return ;
        }

        //初始化
        LinkedNode pre = head;
        LinkedNode cur = head.next;

        HashSet<Integer> set = new HashSet<Integer>();
        set.add(head.value);
        while (cur!=null)
        {
            if (set.contains(cur.value))
            {
                pre.next = cur.next;
            }
            else
            {
                set.add(cur.value);
                pre = cur;
            }
            cur = cur.next;
        }

打印兩個(gè)有序鏈表的公共節(jié)點(diǎn)

題目:提供兩個(gè)有序鏈表的頭指針head1和head2,打印兩個(gè)鏈表的公共部分阁将。

    public void print(LinkedNode head1,LinkedNode head2)
    {
        while (head1!=null&&head1!=null)
        {
            if (head1.value<head2.value)
            {
                head1=head1.next;
            }else if (head1.value>head2.value)
            {
                head2=head2.next;
            }else
            {
                System.out.println(head1.value);
                head1 = head1.next;
                head2 = head2.next;
            }
        }

    }

反轉(zhuǎn)鏈表

題目:輸入一個(gè)鏈表膏秫,反轉(zhuǎn)鏈表后,輸出鏈表的所有元素做盅。

解題思路:

  • 當(dāng)前節(jié)點(diǎn)是head缤削,pre為當(dāng)前節(jié)點(diǎn)的前?節(jié)點(diǎn),next為當(dāng)前節(jié)點(diǎn)的下?節(jié)點(diǎn)
  • 需要pre和next的?目的是讓當(dāng)前節(jié)點(diǎn)從pre->head>next1->next2變成pre<-head next1->next2
  • 先保存head.next的節(jié)點(diǎn)吹榴,然后將head.next=pre換成前一個(gè)節(jié)點(diǎn)的引用
  • 然后pre = head,head = next亭敢,進(jìn)行節(jié)點(diǎn)的遍歷替換
  • 如果head為null的時(shí)候,pre就為最后一個(gè)節(jié)點(diǎn)了了图筹,但是 鏈表已經(jīng)反轉(zhuǎn)完畢帅刀,pre就是反轉(zhuǎn)后鏈表的第一個(gè)節(jié)點(diǎn)
    public LinkedNode reverse(LinkedNode head)
    {

        if (head==null)
        {
            return null;
        }

        //初始化前后指標(biāo)節(jié)點(diǎn)
        LinkedNode pre = null;
        LinkedNode next = null;
        while (head!=null)
        {
            next = head.next;
            head.next = pre;
            //head--> null

            pre = head;
            head = next;
        }

        return pre;
    }

輸入一個(gè)鏈表,輸出該鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)远剩。

  • 這道題的難點(diǎn)在于不不知道k結(jié)點(diǎn)的位置扣溺。
  • 我們可以使?用兩個(gè)指針,第一個(gè)指針先跑k-1 ,然后兩個(gè)指針再一起跑
  • 等到第一個(gè)指針到終點(diǎn)時(shí)瓜晤,第二個(gè)指針距終點(diǎn)也就是倒數(shù)第k個(gè)結(jié)點(diǎn)

定義兩個(gè)指針娇妓,我們都知道倒數(shù)第k個(gè)距離最后一個(gè)的距離是k-1,所以可以先移動(dòng)一個(gè)指針走k步后活鹰,然后兩個(gè)指針同時(shí)移動(dòng)哈恰,那么在快的指針到達(dá)結(jié)尾時(shí),慢的指針到達(dá)的位置正好是倒數(shù)第k個(gè)志群。

    public LinkedNode FindKthNode(LinkedNode head,int k)
    {

        //定義兩個(gè)指針
        LinkedNode point1 = head;
        LinkedNode point2 = head;

        int a = k;//記錄k值的變化
        int count = 0;//記錄節(jié)點(diǎn)的數(shù)目


        while (point1!=null)
        {
            point1 = point1.next;
            count++;
            if (k<1) //說明此事point1已經(jīng)到正向k的位置
            {
                point2 = point2.next; //指針2開始
            }
            k--; //point1每次走一次都要減去1
        }

        if (count<a)
            //如果節(jié)點(diǎn)個(gè)數(shù)?小于所求的倒數(shù)第k個(gè)節(jié)點(diǎn)着绷,則返回null
        {
            return null;
        }

        return  point2;
    }

附加

二分查找

注意點(diǎn):

  • mid的計(jì)算方式采用a+(b-a)/2
  • 理由是:當(dāng)a和b的值過大的情況會(huì)出現(xiàn)溢出的情況,所以這里采用改進(jìn)
  public static int binSearch(int[] arr,int k){
        int low = 0;
        int high = arr.length;
        //注意high的取值是arr.length或arr.length-1,對(duì)于循環(huán)體的處理不同
        while (high>low)
        {
            int mid = low+(high-low)/2; //(low+high)/2 當(dāng)兩個(gè)數(shù)很大的情況可能出現(xiàn)溢出
            if (arr[mid]>k)  // [low,mid)
            {
                high = mid;
            }else if (arr[mid]<k)
            {
                low = mid+1;
            }else 
                  return mid;
        }
        return -1;
    }

樹的定義

package com.joyo.code;

public class TreeNode {
    private final char value;
    private TreeNode left;
    private TreeNode right;

    public TreeNode(char value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }

    public char getValue() {
        return value;
    }

    public TreeNode getLeft() {
        return left;
    }

    public void setLeft(TreeNode left) {
        this.left = left;
    }

    public TreeNode getRight() {
        return right;
    }

    public void setRight(TreeNode right) {
        this.right = right;
    }
}

創(chuàng)建樹

二叉樹
public TreeNode treeCreator()
    {
        TreeNode root = new TreeNode('A');
        root.setLeft(new TreeNode('B'));
        root.getLeft().setLeft(new TreeNode('D'));
        root.getLeft().setRight(new TreeNode('E'));
        root.getLeft().getRight().setLeft(new TreeNode('G'));
        root.setRight(new TreeNode('C'));
        root.getRight().setRight(new TreeNode('F'));
        return root;
    }

樹的遍歷(前序锌云、中序荠医、后序)

主要還是通過遞歸的思想來進(jìn)行遍歷,前中后就是調(diào)整語句的執(zhí)行順序

前序

 //前序遍歷
    public static void  preOrder(TreeNode root){
        if (root==null)
        {
            return;
        }
        System.out.print(root.getValue());
        preOrder(root.getLeft());
        preOrder(root.getRight());
    }

中序

  //中序遍歷
    public void inOrder(TreeNode root){
        if (root==null)
        {
            return;
        }
        inOrder(root.getLeft());
        System.out.print(root.getValue());
        inOrder(root.getRight());
    }

后序

//后續(xù)遍歷
    public void postOrder(TreeNode root){
        if (root==null)
        {
            return;
        }
        postOrder(root.getLeft());
        postOrder(root.getRight());
        System.out.print(root.getValue());
    }

輸出結(jié)果:
前序:ABDEGCF
中序:DBGEACF
后序:DGEBFCA

根據(jù)前序中序輸出后序

注意點(diǎn):

  • 縮小范圍桑涎,尋找遞歸的執(zhí)行區(qū)域
  • 前序和中序可以確認(rèn)樹的結(jié)構(gòu)彬向,但是前序和后序無法唯一性確定好二叉樹的結(jié)構(gòu)


    遞歸縮小求解范圍
public String postPrint(String pre,String in){
        if (pre.isEmpty()){
            return "";
        }
        char rootNode = pre.charAt(0);
        int indexNode = in.indexOf(rootNode);
        return postPrint(pre.substring(1,indexNode+1),in.substring(0,indexNode))+
                postPrint(pre.substring(indexNode+1),in.substring(indexNode+1))+
                rootNode;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市攻冷,隨后出現(xiàn)的幾起案子娃胆,更是在濱河造成了極大的恐慌,老刑警劉巖等曼,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件里烦,死亡現(xiàn)場離奇詭異,居然都是意外死亡禁谦,警方通過查閱死者的電腦和手機(jī)胁黑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來州泊,“玉大人丧蘸,你說我怎么就攤上這事∫T恚” “怎么了力喷?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長渴肉。 經(jīng)常有香客問我冗懦,道長,這世上最難降的妖魔是什么仇祭? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任披蕉,我火速辦了婚禮,結(jié)果婚禮上乌奇,老公的妹妹穿的比我還像新娘没讲。我一直安慰自己,他們只是感情好礁苗,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布爬凑。 她就那樣靜靜地躺著,像睡著了一般试伙。 火紅的嫁衣襯著肌膚如雪嘁信。 梳的紋絲不亂的頭發(fā)上于样,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音潘靖,去河邊找鬼穿剖。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卦溢,可吹牛的內(nèi)容都是我干的糊余。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼单寂,長吁一口氣:“原來是場噩夢啊……” “哼贬芥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宣决,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤蘸劈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后疲扎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昵时,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年椒丧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壹甥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壶熏,死狀恐怖句柠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棒假,我是刑警寧澤溯职,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站帽哑,受9級(jí)特大地震影響谜酒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜妻枕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一僻族、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屡谐,春花似錦述么、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饵撑,卻和暖如春剑梳,著一層夾襖步出監(jiān)牢的瞬間唆貌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工阻荒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挠锥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓侨赡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親粱侣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子羊壹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 什么是數(shù)組? 數(shù)組簡單來說就是將所有的數(shù)據(jù)排成一排存放在系統(tǒng)分配的一個(gè)內(nèi)存塊上齐婴,通過使用特定元素的索引作為數(shù)組的下...
    啟明_b56f閱讀 918評(píng)論 0 0
  • //leetcode中還有花樣鏈表題油猫,這里幾個(gè)例子,冰山一角 求單鏈表中結(jié)點(diǎn)的個(gè)數(shù)----時(shí)間復(fù)雜度O(n)這是最...
    暗黑破壞球嘿哈閱讀 1,521評(píng)論 0 6
  • 搞懂單鏈表常見面試題 Hello 繼上次的 搞懂基本排序算法柠偶,這個(gè)一星期情妖,我總結(jié)了,我所學(xué)習(xí)和思考的單鏈表基礎(chǔ)知識(shí)...
    醒著的碼者閱讀 4,591評(píng)論 1 45
  • 寂寂空山路冷清诱担,叢叢野菊笑相迎毡证。 寒香素淡凝朝露,霜蕊恬和蘊(yùn)晚晴蔫仙。 不與春花爭爛漫料睛,卻教秋蝶獨(dú)鐘情。 豪放獨(dú)綻嘯山...
    逸塵居士閱讀 452評(píng)論 0 0
  • 在這里想先解釋一下為什么(只)考慮性別差異摇邦。 雖說男女之間其實(shí)相同遠(yuǎn)多于差異(心理課上老師們也強(qiáng)調(diào)過“火星金星”之...
    潛_921f閱讀 699評(píng)論 0 0