首页 > 代码库 > leetCode解题报告5道题(八)

leetCode解题报告5道题(八)

题目一:

Populating Next Right Pointers in Each Node

 

Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Note:

  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,
Given the following perfect binary tree,

         1
       /        2    3
     / \  /     4  5  6  7

After calling your function, the tree should look like:

         1 -> NULL
       /        2 -> 3 -> NULL
     / \  /     4->5->6->7 -> NULL

分析:

题意给我们一棵“完全二叉树”,让我们把二叉树中每个结点的next域根据如例子那样给它赋值。

看到这个题目,我们的第一反应可能是

1、层次遍历二叉树(这样要用到一个queue队列,并不满足题意的对空间的要求)

2、递归方法(这个是可以的)

但因为这道题目很特殊,二叉树是一棵完全二叉树,所以我们现在要用循环迭代的方法来求解这道题。

具体看代码中的注释

AC代码:

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void connect(TreeLinkNode root) {
        if (root == null)
            return ;
        //每一层的最左边的那个结点
        TreeLinkNode leftNode = root;
        while (leftNode != null){
            //把同一层的结点用next串起来
            TreeLinkNode nowNode = leftNode;
            while (nowNode != null){
                //左孩子的next域指向右孩子
                if (nowNode.left != null){
                    nowNode.left.next = nowNode.right;
                }
                //如果一个结点nowNode的右孩子不为空,却这个结点nowNode还有兄弟的话
                //那么结点nowNode的右孩子的next域要指向兄弟结点的left域
                if (nowNode.right != null && nowNode.next != null){
                    nowNode.right.next = nowNode.next.left;
                }
                //处理结点nowNode的右兄弟(如果为null则不处理)
                nowNode = nowNode.next;
            }
            leftNode = leftNode.left;
        }
    }
    
}


题目二:

Populating Next Right Pointers in Each Node II

 

Follow up for problem "Populating Next Right Pointers in Each Node".

What if the given tree could be any binary tree? Would your previous solution still work?

Note:

  • You may only use constant extra space.

For example,
Given the following binary tree,

         1
       /        2    3
     / \        4   5    7

After calling your function, the tree should look like:

         1 -> NULL
       /        2 -> 3 -> NULL
     / \        4-> 5 -> 7 -> NULL

分析:

这题跟上面那个题目的区别在于条件“所给二叉树并不一定是完全二叉树”了,这样子,在上一题的基础上,我们需要去找到每一层的第一个结点,找到这个第一个满足的结点,其他的思路跟上一题是一样的。

AC代码:

/**
 * Definition for binary tree with next pointer.
 * public class TreeLinkNode {
 *     int val;
 *     TreeLinkNode left, right, next;
 *     TreeLinkNode(int x) { val = x; }
 * }
 */
public class Solution {
    public void connect(TreeLinkNode root) {
        if (root == null)
            return ;
        //每一层的第一个结点
        TreeLinkNode firstNode = root;
        
        while (firstNode != null){
            TreeLinkNode nowNode = firstNode;
            
            //找到第一个不为null的结点.
            TreeLinkNode tempNode = null;
            while (nowNode != null){
                if (nowNode.left != null){
                   tempNode = nowNode.left;
                   break;
                }
                if (nowNode.right != null){
                   tempNode = nowNode.right;
                   break;
                }
                nowNode = nowNode.next;
            }
            
            //下一层要开始的第一个parent结点
            firstNode = tempNode;
            
            //把这一层的所有结点用next域串起来
            while (nowNode != null){
                if (nowNode.left != null && nowNode.left != tempNode){
                    tempNode.next = nowNode.left;
                    tempNode = nowNode.left;
                }
                if (nowNode.right != null && nowNode.right != tempNode){
                    tempNode.next = nowNode.right;
                    tempNode = nowNode.right;
                }
                nowNode = nowNode.next;
            }
        }
    }
}


题目三:

Pascal‘s Triangle

 

Given numRows, generate the first numRows of Pascal‘s triangle.

For example, given numRows = 5,
Return

[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]

AC代码:

public class Solution {
    public ArrayList<ArrayList<Integer>> generate(int numRows) {
        ArrayList<ArrayList<Integer>> arrays = new ArrayList<ArrayList<Integer>>();
        for(int i=0; i<numRows; ++i){
            ArrayList<Integer> list = new ArrayList<Integer>();
            for (int j=0; j<=i; ++j){
                if (j == 0 || j == i){
                    list.add(1);
                }else{
                    ArrayList<Integer> temp = arrays.get(i-1);
                    int left = temp.get(j-1);
                    int right = temp.get(j);
                    list.add(left+right);
                }
            }
            arrays.add(list);
        }
        return arrays;
    }
}


题目四:Pascal‘s Triangle II

Given an index k, return the kth row of the Pascal‘s triangle.

For example, given k = 3,
Return [1,3,3,1].

Note:
Could you optimize your algorithm to use only O(k) extra space?


分析:

这道题目和上面那道题目的思路基本上是一样的arrays[i] = arrays[i] + arrays[i-1].

但是由于题目要求给我们的空间就O(k),也就是说当我们想改变下一行的值arrays[i]的话我们必须从中间向左边改变,然后右边用r-i 来对称设置值,程序一开始我们先设置出k个位置的值,每个值都为1。


比如 我们要求的K=4 则

r <= k;

r=0:   [1,1,1,1,1]

r=1: [1,1,1,1,1];

r=2:[1,2,1,1,1];

r=3:[1,3,3,1,1];

k=4 :[1,4,6,4,1]

大家看看我的代码,如果我们不用 “从中间向左边改变,然后右边用r-i 来对称设置值”这样的话,会出现什么问题!


AC代码:

public class Solution {
    public ArrayList<Integer> getRow(int rowIndex) {
        //csdn : http://blog.csdn.net/ljphhj
        ArrayList<Integer> list = new ArrayList<Integer>();
        for (int i=0; i<=rowIndex; ++i){
            list.add(1);
        }
        for(int i=0; i<=rowIndex; ++i){
            //从中间i/2往左移动设置
            //避免你从左向中间时,你计算的当前值会影响到下一个位的计算
            for (int j=i/2; j>=0; --j){
                if (j != 0 && j != i){
                    int left = list.get(j-1);
                    int right = list.get(j);
                    list.set(j, left+right);//设置值
                    list.set(i-j, left+right);//对称另一边的值
                }
            }
        }
        return list;
    }
}

题目五:

Triangle

 

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.


分析:

这题为典型的DP问题,求最短路径长度,也可以用递归的方法来求.

设用一个数组arr[i][j] 来存储这个三角形。


主要思想:动态规划通常用来求最优解,能用动态规划解决的求最优解问题,必须满足,最优解的每个局部解也都是最优的。以上题为例,最佳路径上面的每个数字到底部的那一段路径,都是从该数字出发到达到底部的最佳路径。

则从三角形的最后一行向上求出每个点对应的最短路径,并把值存下来,最终arr[0][0]就为我们要得到的值

此题目中

最后一行的arr[3][]  = {4,1,8,3};

则当到倒数第二行时,每个结点arr[2][i] 的最短路径为 arr[2][i] =  min{arr[2][i] + arr[2+1][i]  ,  arr[2][i] + arr[2+1][i+1] };

这样我们就可以得到倒数第二行的所有点到叶子的最短路径长度了,一直往上,直到第一行就得到了最后的结果arr[0][0]


AC代码:

public class Solution {
    public int minimumTotal(ArrayList<ArrayList<Integer>> triangle) {
        int len1 = triangle.size();
        //从倒数第二行起始
        for (int i=len1-2; i>=0; i--){
            ArrayList<Integer> listUp = triangle.get(i);//当前行
            ArrayList<Integer> listDown = triangle.get(i+1);//当前行的下一行
            for (int j=0; j<listUp.size(); ++j){
                int left = listDown.get(j);
                int right = listDown.get(j+1);
                int min = left > right ? right+listUp.get(j) : left+listUp.get(j);
                listUp.set(j, min);
            }
        }
        return triangle.get(0).get(0);
    }
}