123

題2: 實(shí)現(xiàn)單例類 - done

題3: 二維數(shù)據(jù)查找 - done
題14: 調(diào)整數(shù)組順序糙及,使奇數(shù)在前偶數(shù)在后 - done
題20: 順時(shí)針打印數(shù)組- done
題29: 數(shù)組中出現(xiàn)次數(shù)超過一半的數(shù)字 - done
題30: 最小的K個(gè)數(shù) - done
題31: 連續(xù)子數(shù)組和的最大值 - done
題41: 有序數(shù)組查找“和為s”的兩個(gè)數(shù) - done
題51: 數(shù)組中重復(fù)的數(shù)字 - done

分析規(guī)律+快排定位的方法


題5: 單鏈表反向打印 - done
題13: 在O(1)時(shí)間刪除單鏈表節(jié)點(diǎn) - done
題15: 單鏈表查找倒數(shù)第k個(gè)節(jié)點(diǎn) - done
題16: 單鏈表反轉(zhuǎn) - done
題17: 合并兩個(gè)升序單鏈表 - done
題37: 兩個(gè)單鏈表的第一個(gè)公共節(jié)點(diǎn) - done

遞歸+多個(gè)指針


題7: 兩個(gè)棧實(shí)現(xiàn)隊(duì)列 - done
題7.1: 兩個(gè)隊(duì)列實(shí)現(xiàn)棧 - done

題9: 斐波那契數(shù)列 - done
題10: 二進(jìn)制中1的個(gè)數(shù) - done
題40: 數(shù)組中只出現(xiàn)一次的數(shù) - done
題45: 約瑟夫問題 - done
題47: 不用加減乘除實(shí)現(xiàn)加法 - done
題47.1: 不使用新的變量练俐,交換兩個(gè)變量的值 - done

總結(jié)出數(shù)學(xué)公式+位運(yùn)算+遞歸


題35: 第一個(gè)只出現(xiàn)一次的字符 - done

題58: 二叉樹的下一個(gè)節(jié)點(diǎn)
題58: 判斷一個(gè)二叉樹是否對(duì)稱
題60: 二叉樹打印成多行
題61: 之字形打印二叉樹
題62: 二叉搜索樹的第k個(gè)節(jié)點(diǎn)
題62.1: 二叉樹中序遍歷

題2: 實(shí)現(xiàn)單例類

單例模式:

  1. 單例類確保該類只有唯一一個(gè)實(shí)例
  2. 單例類自己創(chuàng)建這一實(shí)例
  3. 單例類給所有其他對(duì)象提供這一實(shí)例

最簡(jiǎn)單的實(shí)現(xiàn)方式

// 餓漢式單例
public class Single {
    
    private static Single single = new Single();

    private Single() {

    }

    public static Single getSingle() {
        return single;
    }
}

解釋

  1. static變量也叫靜態(tài)變量朝聋,靜態(tài)變量被所有的對(duì)象所共享禾锤,在內(nèi)存中只有一個(gè)副本颖系。餓漢式單例在類加載初始化時(shí)就創(chuàng)建好一個(gè)靜態(tài)的對(duì)象供外部使用哩治,除非系統(tǒng)重啟,這個(gè)對(duì)象不會(huì)改變衷快,所以本身就是線程安全的。
  2. 構(gòu)造方法限定為private避免了類在外部被實(shí)例化
  3. Single類的唯一實(shí)例只能通過getSingle()方法訪問

缺點(diǎn)
無論這個(gè)類是否被使用姨俩,都會(huì)被實(shí)例化蘸拔,浪費(fèi)內(nèi)存

較好的實(shí)現(xiàn)方式

public class Single1 {
    // volatile保證不同線程對(duì)這個(gè)變量進(jìn)行操作時(shí)的可見性
    // 即一個(gè)線程修改了某個(gè)變量的值师郑,這新值對(duì)其他線程來說是立即可見的
    private volatile static Single1 single1 = null;

    private Single1() {

    }

    public static Single1 getSingle1() {
        // 如果每次執(zhí)行g(shù)etSingle1都加鎖,很影響性能
        // 因此先判斷调窍,如果null宝冕,加鎖初始化,如果非null邓萨,直接返回
        if (single1 == null) {
            synchronized (Single1.class) { // 鎖地梨,保證線程安全
                if (single1 == null) {
                    single1 = new Single1();
                }
            }
        }
        return single1;
    }
}

https://www.cnblogs.com/limingluzhu/p/5156659.html


題3: 二維數(shù)組查找
題14: 調(diào)整數(shù)組順序,使奇數(shù)在前偶數(shù)在后
    // 調(diào)整數(shù)組順序缔恳,使奇數(shù)在前偶數(shù)在后
    private static void handleArr(int[] arr) {
        if (arr == null) {
            return;
        }

        int start = 0;
        int end = arr.length - 1;
        int tem;
        while (start != end) {
            if ((arr[start] & 1) == 1) { // 奇數(shù)
                start++;
            }else { // 偶數(shù)
                tem = arr[start];
                arr[start] = arr[end];
                arr[end] = tem;
                end--;
            }
        }
    }
題20: 順時(shí)針打印數(shù)組

思路:確定圈數(shù)宝剖,針對(duì)圈中每條邊分別打印,注意邊界

    // 順時(shí)針打印數(shù)組
    private static void circlePrintArr(int[][] arr) {
        if (arr == null || arr.length <= 0 || arr[0].length <= 0) {
            return;
        }
        int row = arr.length; // 總行數(shù)
        int col = arr[0].length; // 總列數(shù)
        int totalCir = (Math.min(row, col) + 1) >> 1; // 一共打印的圈數(shù)
        for (int start = 0; start < totalCir; start++) {
            printCircle(arr, row, col, start);
        }
    }

    // row總行數(shù)歉甚,col總列數(shù)万细,start當(dāng)前圈數(shù)
    private static void printCircle(int[][] arr, int row, int col, int start) {
        // 邊界:左上角arr[start][start]
        // 邊界:右下角arr[endX][endY]
        int endX = row - start - 1;
        int endY = col - start - 1;

        // 打印上邊
        for (int i = start; i <= endY; i++) {
            System.out.print(arr[start][i] + " ");
        }

        // 打印右邊
        for (int i = start + 1; i <= endX; i++) {
            System.out.print(arr[i][endY] + " ");
        }

        // 打印下邊
        if (endX > start) {
            for (int i = endY - 1; i >= start; i--) {
                System.out.print(arr[endX][i] + " ");
            }
        }

        // 打印左邊
        if (endY > start) {
            for (int i = endX - 1; i >= start + 1; i--) {
                System.out.print(arr[i][start] + " ");
            }
        }
    }
題29: 數(shù)組中出現(xiàn)次數(shù)超過一半的數(shù)字

描述:數(shù)組中又一個(gè)數(shù)字出現(xiàn)的次數(shù),大于數(shù)組長(zhǎng)度的一半纸泄,找出這個(gè)數(shù)
思路一:

  1. 快排定位方法
  2. 定位一次赖钞,如果定位不在中間,則重長(zhǎng)的子數(shù)組在進(jìn)行定位聘裁,直到定位在中間
    思路二:
    時(shí)間復(fù)雜度O(n)
  3. 維護(hù)兩個(gè)數(shù)仁烹,一個(gè)存值,一個(gè)存值出現(xiàn)的次數(shù)
  4. 遍歷數(shù)組咧虎,相同-加次數(shù)卓缰,不同-減次數(shù),次數(shù)為0-更新值
    // 數(shù)組中出現(xiàn)次數(shù)超過一半的數(shù)字
    private static Integer moreThanHalfNum(int[] arr) {
        if (arr == null || arr.length <= 1) {
            return null;
        }

        int key = arr[0];
        int cnt = 1;
        for (int i = 1; i < arr.length; i++) {
            if (cnt == 0) {
                key = arr[i];
                cnt++;
            }else if (arr[i] == key) {
                cnt++;
            }else {
                cnt--;
            }
        }
        return key;
    }
題30: 最小的K個(gè)數(shù)

思路:利用快排的定位方法

  1. 定位砰诵,判斷左邊個(gè)數(shù)如果不為k-1征唬,繼續(xù)定位,直到左邊個(gè)數(shù)為k-1
    // 最小的k個(gè)數(shù)
    private static void leastKNumbers(int[] arr, int k) {
        if (arr == null || k <= 0 || arr.length < k) {
            return;
        }

        int start = 0;
        int end = arr.length - 1;
        int pos = Sort.position(arr, start, end);
        while (pos != k - 1) {
            if (pos > k - 1) {
                end = pos - 1;
            }else {
                start = pos + 1;
            }
            pos = Sort.position(arr, start, end);
        }

        for (int i = 0; i < k; i++) {
            System.out.print(arr[i] + " ");
        }
    }
題31: 連續(xù)子數(shù)組和的最大值

思路:時(shí)間復(fù)雜度O(n)

  1. 用f(i)來表示茁彭,所有以i結(jié)尾的子數(shù)組中总寒,子數(shù)組和的最大值
  2. 那么題目答案轉(zhuǎn)換為,求max(f(i))
  3. 如果f(i-1)小于0理肺,那么f(i) = arr[i]摄闸,如果f(i-1)大于0,那么f(i) = f(i-1) + arr[i]
    // 連續(xù)子數(shù)組妹萨,和的最大值
    private static Integer findMax(int[] arr) {
        if (arr == null || arr.length == 0) {
            return null;
        }

        int sum = 0; // f(i)
        int arrMax = 0x80000000; // max(f(i))
        for (int i = 0; i <= arr.length - 1; i++) {
            if (sum <= 0) {
                sum = arr[i];
            }else {
                sum = sum + arr[i];
            }

            if (sum > arrMax) {
                arrMax = sum;
            }
        }
        return arrMax;
    }
題41: 有序數(shù)組查找“和為s”的兩個(gè)數(shù)

思路:頭尾兩個(gè)指針

    // 有序數(shù)組查找“和為s”的兩個(gè)數(shù)
    private static boolean findNumWithSum(int[] arr, int sum) {
        if (arr == null || arr.length < 2) {
            return false;
        }

        int start = 0;
        int end = arr.length - 1;
        int curSum;
        while (end > start) {
            curSum = arr[start] + arr[end];
            if (curSum == sum) {
                System.out.println(arr[start]);
                System.out.println(arr[end]);
                return true;
            }else if (curSum > sum) {
                end--;
            }else {
                start++;
            }
        }
        return false;
    }
題51: 數(shù)組中重復(fù)的數(shù)字

描述:長(zhǎng)度為n的數(shù)組年枕,沒個(gè)數(shù)都在[0, n-1]內(nèi),求數(shù)組中是否有重復(fù)數(shù)字
思路:分析數(shù)組規(guī)律乎完,如果數(shù)組中沒有重復(fù)數(shù)字熏兄,那么下標(biāo)為i的位置,值也為i

    // 數(shù)組中重復(fù)的數(shù)字
    private static boolean isRepeat(int[] arr) {
        if (arr == null || arr.length == 0) {
            return false;
        }

        int tem;
        for (int i = 0; i < arr.length; i++) {
            while (arr[i] != i) {
                if (arr[i] == arr[arr[i]]) {
                    System.out.println(arr[i]);
                    return true;
                }
                tem = arr[i];
                arr[i] = arr[tem];
                arr[tem] = tem;
            }
        }
        return false;
    }

題5: 單鏈表反向打印

提示:遞歸

    private static void reverseList(Node node) {
        if (node == null) {
            return;
        }
        if (node.next == null) {
            System.out.println(node.num);
            return;
        }
        reverseList(node.next);
        System.out.println(node.num);
    }
題13: 在O(1)時(shí)間刪除單鏈表節(jié)點(diǎn)

描述:假定待刪除節(jié)點(diǎn)在給定鏈表內(nèi)
思路:有O(1)的時(shí)間要求,不能遍歷摩桶,可以用“待刪除節(jié)點(diǎn)的next節(jié)點(diǎn)”的內(nèi)容桥状,覆蓋“待刪除節(jié)點(diǎn)”的內(nèi)容。

比如

  • 給定鏈表:n1 -> n2 -> n3 -> n4 -> null
  • 刪除節(jié)點(diǎn):n2
    此時(shí)一定不能用n2 = n3硝清,因?yàn)閚2 = n3達(dá)到的效果如下圖辅斟,n2原來指向b93,執(zhí)行n2 = n3后芦拿,n2指向80c士飒,而原鏈表并沒有變化


    IMG_4117.JPG

    而應(yīng)該用n3的內(nèi)容覆蓋n2的內(nèi)容,然后刪除n3

    // O(1)時(shí)間內(nèi)刪除單鏈表節(jié)點(diǎn)
    private static void delNode(Node head, Node delNode) {
        if (head == null || delNode == null) {
            return;
        }

        Node tem;
        // 待刪除節(jié)點(diǎn)不是尾節(jié)點(diǎn)
        if (delNode.next != null) {
            tem = delNode.next;
            delNode.num = tem.num;
            delNode.next = tem.next;
        }else if (head != delNode){ // 待刪除節(jié)點(diǎn)不是頭節(jié)點(diǎn)防嗡,是尾節(jié)點(diǎn)
            tem = head;
            while (tem.next != delNode) {
                tem = tem.next;
            }
            tem.next = null;
            delNode = null;
        }else { // 鏈表長(zhǎng)度1变汪,刪除頭節(jié)點(diǎn)
            head = null;
            delNode = null;
        }
        tem = null;
    }

雖然有一種場(chǎng)景需要遍歷n-1侠坎,但是平均時(shí)間復(fù)雜度仍然是O(1)蚁趁,不再解釋

題15: 單鏈表查找倒數(shù)第k個(gè)節(jié)點(diǎn)

思路:先做條件判斷,以免程序崩潰

  • 鏈表為空
  • k <= 0
  • k大于鏈表長(zhǎng)度
    // 單鏈表倒數(shù)第k個(gè)節(jié)點(diǎn)
    private static Node findKTail(Node head, int k) {
        if (head == null || k <= 0) {
            return null;
        }

        Node fast = head;
        // 快慢指針实胸,快指針先走k-1步
        for (int i = 0; i < k - 1; i++) {
            fast = fast.next;
            if (fast == null) { // k大于鏈表長(zhǎng)度
                return null;
            }
        }

        Node slow = head;
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
題16: 單鏈表反轉(zhuǎn)

思路:三個(gè)指針

    private Node singleListRoll(Node node) {
        if (node == null) {
            return null;
        }

        Node pre = null;
        Node cur = node;
        Node nex;
        while(cur != null) {
            nex = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nex;
        }
        return pre;
    }
題17: 合并兩個(gè)升序單鏈表

思路:用遞歸做

    // 合并兩個(gè)升序鏈表
    private static Node merge1(Node h1, Node h2) {
        if (h1 == null) {
            return h2;
        }
        if (h2 == null) {
            return h1;
        }

        Node h = null;
        if (h1.num <= h2.num) {
            h = h1;
            h.next = merge1(h1.next, h2);
        }else {
            h = h2;
            h.next = merge1(h1, h2.next);
        }
        return h;
    }
題37: 兩個(gè)單鏈表的第一個(gè)公共節(jié)點(diǎn)

思路:時(shí)間復(fù)雜度O(n)

  1. 先得到兩個(gè)鏈表長(zhǎng)度
  2. 長(zhǎng)鏈表先走
  3. 兩個(gè)鏈表一起走他嫡,第一個(gè)相同
    // 兩個(gè)單鏈表第一個(gè)相同節(jié)點(diǎn)
    private static Node findFirstNode(Node h1, Node h2) {
        if (h1 == null || h2 == null) {
            return null;
        }
        int l1 = nodeLength(h1);
        int l2 = nodeLength(h2);
        Node longNode = h1;
        Node shorNode = h2;
        int dif = l1 - l2;

        if (l2 > l1) {
            longNode = h2;
            shorNode = h1;
            dif = l2 - l1;
        }

        for (int i = 0; i < dif; i++) {
            longNode = longNode.next;
        }

        while (longNode != null && shorNode != null) {
            if (longNode == shorNode) {
                break;
            }
            longNode = longNode.next;
            shorNode = shorNode.next;
        }
        return longNode;
    }

    private static int nodeLength(Node node) {
        int l = 0;
        Node n = node;
        while (n != null) {
            l++;
            n = n.next;
        }
        return l;
    }

題7: 兩個(gè)棧實(shí)現(xiàn)隊(duì)列

思路:

  1. 兩個(gè)棧,一個(gè)做“入椔辏”钢属,一個(gè)做“出棧”
  2. “出椕徘”為空淆党,“入棧”數(shù)據(jù)導(dǎo)入到“出椦攘梗”染乌,繼續(xù)
public class WQueue {
    private Stack<Integer> stack1 = new Stack<Integer>();
    private Stack<Integer> stack2 = new Stack<Integer>();

    // 在隊(duì)列尾部插入元素
    public void appendTail(int num) {
        stack1.push(num);
    }

    // 從隊(duì)列頂部刪除一個(gè)元素
    public Integer deleteHead() throws Exception {
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.pop()); // push入棧,pop出棧
            }
        }
        if (stack2.empty()) {
            throw new Exception("something wrong");
        }
        return stack2.pop();
    }
}
題7.1: 兩個(gè)隊(duì)列實(shí)現(xiàn)棧

思路:

  1. 任何時(shí)候都維持“一個(gè)隊(duì)列空懂讯,另一個(gè)隊(duì)列非空”
  2. 出棧時(shí)荷憋,把“非空隊(duì)列”除隊(duì)尾外的數(shù)據(jù),導(dǎo)入“空隊(duì)列”褐望,刪除“非空隊(duì)列”對(duì)尾元素
// 兩個(gè)隊(duì)列實(shí)現(xiàn)棧
public class WStack {
    private Queue<Integer> queue1 = new LinkedList<Integer>();
    private Queue<Integer> queue2 = new LinkedList<Integer>();

    // 入棧
    public void append(int num) {
        if (queue1.isEmpty()) {
            queue2.offer(num); // offer入隊(duì)列勒庄,poll出隊(duì)列
        }else {
            queue1.offer(num);
        }
    }

    // 出棧
    public Integer delete() {
        Integer res = null;
        if (!queue1.isEmpty()) {
            while (queue1.size() > 1) {
                queue2.offer(queue1.poll());
            }
            res = queue1.poll();
        }else if (!queue2.isEmpty()) {
            while (queue2.size() > 1) {
                queue1.offer(queue2.poll());
            }
            res = queue2.poll();
        }
        return res;
    }
}

題9: 斐波那契數(shù)列

f(0) = 0
f(1) = 1
f(n) = f(n-1) + f(n-2)
解法一:遞歸

    // 斐波那契數(shù)列
    private static int fibo(int n) {
        if (n < 0) {
            return 0;
        }

        if (n <= 1) {
            return n;
        }

        return fibo(n - 1) + fibo(n - 2);
    }

上述解法存在很多重復(fù)計(jì)算,比如計(jì)算f(7)瘫里,需要計(jì)算3次f(4)实蔽,隨著n的增大,重復(fù)計(jì)算節(jié)點(diǎn)會(huì)指數(shù)遞增谨读,而直接計(jì)算反而好些
解法二:直接計(jì)算

    // 斐波那契數(shù)列
    private static int fibo1(int n) {
        if (n < 0) {
            return 0;
        }

        if (n <= 1) {
            return n;
        }

        int n1 = 0;
        int n2 = 1;
        int sum = n1 + n2;
        for (int i = 2; i <= n; i++) {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
        return sum;
    }

很多問題可以轉(zhuǎn)化為斐波那契數(shù)列盐须,遇到問題先分析規(guī)律,先走一步找規(guī)律

題10: 二進(jìn)制中1的個(gè)數(shù)

輸入int數(shù),輸出二進(jìn)制中1的個(gè)數(shù)
思路:

  1. 不能用除以2贼邓,因?yàn)樨?fù)數(shù)的時(shí)候會(huì)出錯(cuò)阶冈,比如-1的二進(jìn)制是32個(gè)1,應(yīng)該輸出32
  2. 每一位都做&運(yùn)算
    // 二進(jìn)制中1的個(gè)數(shù)
    private static int numOf1(int n) {
        int cnt = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) == flag) {
                cnt++;
            }
            flag = flag << 1;
        }
        return cnt;
    }

tips:把一個(gè)整數(shù)減去1塑径,在和原來的整數(shù)做&運(yùn)算女坑,得到的結(jié)果相當(dāng)于把整數(shù)的二進(jìn)制表示中最右邊的一個(gè)1變?yōu)?,很多問題可以用這個(gè)思路解決

題40: 數(shù)組中只出現(xiàn)一次的數(shù)

描述:給定數(shù)組统舀,只有兩個(gè)數(shù)只出現(xiàn)一次匆骗,其余數(shù)均出現(xiàn)了兩次,找出這兩個(gè)數(shù)
思路:

  1. 任何一個(gè)數(shù)字異或它自己都等于0誉简,異或滿足結(jié)合律
  2. 如果數(shù)組中“只有一個(gè)數(shù)字只出現(xiàn)一次”碉就,那么把整個(gè)數(shù)組異或一邊,就能得到要找的數(shù)字
  3. 如果數(shù)組中“只有一個(gè)數(shù)字只出現(xiàn)一次”闷串,嘗試把數(shù)字分為兩部分瓮钥,每部分“只有一個(gè)數(shù)字出現(xiàn)一次”
  4. 這兩個(gè)數(shù)字是不同的,因此他們異或的結(jié)果烹吵,二進(jìn)制一定有一位是1碉熄,把這一位作為標(biāo)識(shí)位,把數(shù)組分為兩部分肋拔,問題解決
    // 數(shù)組中只出現(xiàn)一次的數(shù)字
    private static void findTwoInt(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }

        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum ^= arr[i];
        }

        // 找出key1 ^ key2 中為1的位(倒數(shù)第index位)
        int index = 1;
        while ((sum & 1) != 1) {
            sum = sum >> 1;
            index++;
        }

        int key1 = 0;
        int key2 = 0;
        for (int i = 0; i < arr.length; i++) {
            if (splitArr(arr[i], index)) {
                key1 ^= arr[i];
            }else {
                key2 = key2 ^ arr[i];
            }
        }
        System.out.println(key1 + " " + key2);
    }

    private static boolean splitArr(int num, int index) {
        num = num >> (index - 1);
        return (num & 1) == 1;
    }
題45: 約瑟夫問題

描述:0,1...n-1這n個(gè)人按順序排成一個(gè)圓圈锈津,從0開始報(bào)數(shù),報(bào)到m-1的人退出凉蜂,剩下的人繼續(xù)從0開始報(bào)數(shù)琼梆,求最后勝利者的編號(hào)
比如:0,1,2,3,4這五個(gè)數(shù),m=3窿吩,則依次刪除2,0,4,1茎杂,最后3勝出
思路:總結(jié)出數(shù)學(xué)規(guī)律

  1. 用f(n)表示最后勝出的人
  2. 那么第一個(gè)一定是(m-1)%n退出,然后從k=m%n開始爆存,繼續(xù)報(bào)數(shù)
    k, k+1, k+2 ... n-2, n-1, 0, 1, 2 ... k-2
  3. 剩下的問題就完全變?yōu)榱薾-1個(gè)人的新約瑟夫環(huán)問題蛉顽,我們把他們的編號(hào)做一下轉(zhuǎn)換


    IMG_4119.JPG
  4. 原問題的解f(n),等于左邊環(huán)的解(也就是第2步的環(huán)的解先较,這個(gè)好理解)
  5. 另外不管編號(hào)如何變化携冤,最后勝出者的位置是不變的(也就是第3步,左右兩個(gè)環(huán)的解位置相同)
  6. 左邊編號(hào)x'闲勺,到右邊編號(hào)x曾棕,有映射關(guān)系x'=(x+k)%n
  7. 假設(shè)最后的解位于圖標(biāo)出的位置,即
    -- f(n)=x'
    -- f(n-1)=x
    -- x'=(x+k)%n
  8. 于是菜循,f(n)=[f(n-1)+k]%n=[f(n-1)+m]%n (n>1的時(shí)候)
    // 約瑟夫環(huán)
    private static int lastWin(int n, int m) {
        if (n <= 0 || m <= 0) {
            return -1;
        }
        int last = 0;
        for (int i = 2; i <= n; i++) {
            last = (last + m) % i;
        }
        return last;
    }
題47: 不用加減乘除實(shí)現(xiàn)加法

思路:

  1. 二進(jìn)制翘地,加法用異或代替,進(jìn)位用與代替
  2. 如果進(jìn)位到了符號(hào)位,比如0x40000000+0x40000000衙耕,那么將得到0x80000000昧穿,也就是1073741824+1073741824=-2147483648,這是不合理的橙喘,但是如果直接用十進(jìn)制加法得到的也是這個(gè)結(jié)果时鸵,因?yàn)檫@種情況溢出了,所以我們的算法還是正確的
    // 不用加減乘除做加法
    private static int sum(int i1, int i2) {
        int sum; // 不考慮進(jìn)位的和
        int carry; // 進(jìn)位
        do {
            sum = i1 ^ i2;
            carry = (i1 & i2) << 1;

            i1 = sum;
            i2 = carry;
        }while (carry != 0); // 直到?jīng)]有進(jìn)位
        
        return sum;
    }
題47.1: 不使用新的變量厅瞎,交換兩個(gè)變量的值

描述:交換a饰潜、b
思路:

  1. a=a+b; b=a-b; a=a-b;
  2. a=a^b; b=a^b; a=a^b; // 異或的結(jié)合率

題35: 第一個(gè)只出現(xiàn)一次的字符

思路:空間換時(shí)間

    // 第一個(gè)只出現(xiàn)一次的字符
    private static Character firstSingle(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }

        int[] arr = new int[256]; // 下標(biāo)-字符的asscii碼,值-字符出現(xiàn)次數(shù)
        for (int i = 0; i < str.length(); i++) {
            arr[str.charAt(i)] ++;
        }

        for (int i = 0; i < str.length(); i++) {
            if (arr[str.charAt(i)] == 1) {
                return str.charAt(i);
            }
        }
        return null;
    }

題58: 二叉樹的下一個(gè)節(jié)點(diǎn)

描述:給定一個(gè)二叉樹的其中一個(gè)節(jié)點(diǎn)和簸,樹中的節(jié)點(diǎn)除了有指向左右子節(jié)點(diǎn)的指針彭雾,還有一個(gè)指向父節(jié)點(diǎn)的指針,找出中序遍歷的下一個(gè)節(jié)點(diǎn)

題58: 判斷一個(gè)二叉樹是否對(duì)稱

思路:定義一種遍歷方式锁保,根-右-左薯酝。判斷先序遍歷和此遍歷得到的序列是否一致

    private static boolean isSymm(TreeNode root) {
        return isSymm(root, root);
    }

    private static boolean isSymm(TreeNode root1, TreeNode root2) {
        if (root1 == null && root2 == null) {
            return true;
        }
        if (root1 == null || root2 == null) {
            return false;
        }
        if (root1.data != root2.data) {
            return false;
        }
        return isSymm(root1.left, root2.right) && isSymm(root1.right, root2.left);
    }
題60: 二叉樹打印成多行

描述:給定一個(gè)二叉樹,每一層打印一行身诺,每一層打印順序從左到右
思路:用一個(gè)隊(duì)列存放節(jié)點(diǎn)蜜托,用變量控制是否換行

    // 二叉樹打印成多行
    private static void printTree(TreeNode root) {
        if (root == null) {
            return;
        }

        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        int curUnHandle = 1; // 當(dāng)前層未打印個(gè)數(shù)
        int nextTotal = 0; // 下一層總個(gè)數(shù)
        TreeNode node;
        while (!queue.isEmpty()) {
            node = queue.poll();
            System.out.print(node.data + " ");
            curUnHandle--;

            if (node.left != null) {
                queue.offer(node.left);
                nextTotal++;
            }
            if (node.right != null) {
                queue.offer(node.right);
                nextTotal++;
            }

            if (curUnHandle == 0) {
                System.out.println();
                curUnHandle = nextTotal;
                nextTotal = 0;
            }
        }
    }
題61: 之字形打印二叉樹

描述:給定一個(gè)二叉樹抄囚,按之字形打印二叉樹霉赡,即第一行從左到右,第二行從右到左幔托,依次類推
思路:分析規(guī)律穴亏,兩個(gè)棧

    // 二叉樹之字形打印
    private static void printTree2(TreeNode root) {
        if (root == null) {
            return;
        }

        Stack<TreeNode> stack1 = new Stack<TreeNode>(); // 先左后右
        Stack<TreeNode> stack2 = new Stack<TreeNode>(); // 先右后左
        stack1.push(root);
        TreeNode node;
        while (!stack1.empty() || !stack2.empty()) {
            if (!stack1.empty()) {
                while(!stack1.empty()) {
                    node = stack1.pop();
                    System.out.print(node.data + " ");
                    if (node.left != null) {
                        stack2.push(node.left);
                    }
                    if (node.right != null) {
                        stack2.push(node.right);
                    }
                }
                System.out.println();
            }else {
                while (!stack2.empty()) {
                    node = stack2.pop();
                    System.out.print(node.data + " ");
                    if (node.right != null) {
                        stack1.push(node.right);
                    }
                    if (node.left != null) {
                        stack1.push(node.left);
                    }
                }
                System.out.println();
            }
        }
    }
題62: 二叉搜索樹的第k個(gè)節(jié)點(diǎn)

描述:給定二叉排序樹,找出其中第k大的節(jié)點(diǎn)重挑。
思路:二叉排序樹的中序遍歷是從小到大的數(shù)列

題62.1: 二叉樹中序遍歷
    // 二叉樹中序遍歷-遞歸
    private static void midPrintTree1(TreeNode node) {
        if (node == null) {
            return;
        }
        midPrintTree1(node.left);
        System.out.print(node.data + " ");
        midPrintTree1(node.right);
    }

    // 二叉樹中序遍歷-非遞歸
    private static void midPrintTree2(TreeNode node) {
        if (node == null) {
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while(node != null || !stack.empty()) {
            while(node != null) {
                // 前序遍歷在這里打印即可
                stack.push(node);
                node = node.left;
            }
            if(!stack.empty()) {
                node = stack.pop();
                System.out.print(node.data + " ");
                node = node.right;
            }
        }
    }





最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗓化,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谬哀,更是在濱河造成了極大的恐慌刺覆,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件史煎,死亡現(xiàn)場(chǎng)離奇詭異谦屑,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)篇梭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門氢橙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恬偷,你說我怎么就攤上這事悍手。” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵坦康,是天一觀的道長(zhǎng)竣付。 經(jīng)常有香客問我,道長(zhǎng)滞欠,這世上最難降的妖魔是什么卑笨? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮仑撞,結(jié)果婚禮上赤兴,老公的妹妹穿的比我還像新娘。我一直安慰自己隧哮,他們只是感情好桶良,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沮翔,像睡著了一般陨帆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上采蚀,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天疲牵,我揣著相機(jī)與錄音,去河邊找鬼榆鼠。 笑死纲爸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妆够。 我是一名探鬼主播识啦,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼神妹!你這毒婦竟也來了颓哮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤鸵荠,失蹤者是張志新(化名)和其女友劉穎冕茅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛹找,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡姨伤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熄赡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姜挺。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖彼硫,靈堂內(nèi)的尸體忽然破棺而出炊豪,到底是詐尸還是另有隱情凌箕,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布词渤,位于F島的核電站牵舱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏缺虐。R本人自食惡果不足惜芜壁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望高氮。 院中可真熱鬧慧妄,春花似錦、人聲如沸剪芍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)罪裹。三九已至饱普,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間状共,已是汗流浹背套耕。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留峡继,地道東北人冯袍。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鬓椭,于是被迫代替她去往敵國(guó)和親颠猴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子关划,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355