1、删除链表中重复的结点
2、二叉树的下一个结点
3、对称的二叉树
4、按之字形顺序打印二叉树
5、把二叉树打印成多行
6、序列化二叉树
7、二叉搜索树的第k个结点
8、数据流中的中位数
9、滑动窗口的最大值
10、矩阵中的路径
11、机器人的运动范围
1、删除链表中重复的结点
(1)问题描述:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
(2)解题思路:
定义一个新的链表,让新链表头结点的下一个结点指向该链表的头结点;定义两个新结点,分别为新的链表的头头结点和原链表的头结点;在两个新结点中执行重复元素的覆盖赋值;返回新链表头结点.next。
(3)代码实现:
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if (pHead == null)
return null;
ListNode node = new ListNode(0);
node.next = pHead;
ListNode pre = node;
ListNode p = pHead;
while (p!= null && p.next != null){
if (p.val == p.next.val){
int temp = p.val;
while (p != null &&p.val == temp){
p = p.next;
}
pre.next = p;
}else {
pre = p;
p = p.next;
}
}
return node.next;
}
}
2、二叉树的下一个结点
(1)问题描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
(2)解题思路:
如果有右子树,则找右子树的最左节点;没右子树,则向上找第一个是父节点左孩子的节点,返回该节点父节点。
(3)代码实现:
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode == null){
return null;
}
if(pNode.right != null){
pNode = pNode.right;
while(pNode.left != null){
pNode = pNode.left;
}
return pNode;
}
while(pNode.next != null){ //非根节点
if(pNode == pNode.next.left)
return pNode.next;
pNode = pNode.next;
}
return null;
}
3、对称的二叉树
(1)问题描述:
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
(2)解题思路:
左子树的左子树和右子树的右子树相同,左子树的右子树和右子树的左子树相同
(3)代码实现:
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null)
return true;
return comRoot(pRoot.left,pRoot.right);
}
public boolean comRoot(TreeNode left,TreeNode right){
if(left==null)return right==null;
if(right==null)return false;
if(left.val!=right.val)return false;
return comRoot(left.left,right.right)&&comRoot(left.right,right.left);
}
}
4、按之字形顺序打印二叉树
(1)问题描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
(2)解题思路:
层序遍历;
遍历每一层时判断是否需要从右往左打印。
(3)代码实现:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();
if (pRoot == null){
return lists;
}
boolean leftToRight = true;
Queue<TreeNode> layer = new LinkedList<TreeNode>();
ArrayList<Integer> layerList = new ArrayList<Integer>();
layer.add(pRoot);
int start = 0,end = 1;
while (layer.size() > 0){
TreeNode cur = layer.remove();
layerList.add(cur.val);
start++;
if (cur.left != null){
layer.add(cur.left);
}
if (cur.right != null){
layer.add(cur.right);
}
if (start == end){
end = layer.size();
start = 0;
if (!leftToRight){
lists.add(reverse(layerList));
}else {
lists.add(layerList);
}
leftToRight = !leftToRight;
layerList = new ArrayList<Integer>();
}
}
return lists;
}
private ArrayList reverse(ArrayList<Integer> layerlist){
int length = layerlist.size();
ArrayList<Integer> reverseList = new ArrayList<Integer>();
for (int i=length-1;i>=0;i--){
reverseList.add(layerlist.get(i));
}
return reverseList;
}
}
5、把二叉树打印成多行
(1)问题描述:
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
(2)解题思路:
层序遍历
(3)代码实现:
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if(pRoot==null){
return result;
}
LinkedList<TreeNode> link = new LinkedList<TreeNode>();
ArrayList<Integer> list = new ArrayList<Integer>();
link.add(pRoot);
int start = 0, end = 1;
while(!link.isEmpty()){
TreeNode node = link.remove();
list.add(node.val);
start++;
if(node.left!=null){
link.add(node.left);
}
if(node.right!=null){
link.add(node.right);
}
if(start == end){
end = link.size();
start = 0;
result.add(list);
list = new ArrayList<Integer>();
}
}
return result;
}
}
6、序列化二叉树
(1)问题描述:
请实现两个函数,分别用来序列化和反序列化二叉树
(2)解题思路:
根据给出的返回值类型可知,序列化就是:需要将一个二叉树序列化成为一个String类型;
反序列化就是将序列化返回的String字符串返回到原二叉树。
对于序列化:
使用前序遍历,递归的将二叉树的值转化为字符,并且在每次二叉树的结点不为空时,在转化val所得的字符之后添加一个','作为分割。对于空节点则以'#'代替。
对于反序列化:
按照前序顺序,递归的使用字符串中的字符创建一个二叉树。
(3)代码实现:
import java.util.*;
public class Solution {
int index = -1;
String Serialize(TreeNode root) {
StringBuilder sb = new StringBuilder();
if (root == null){
sb.append("#,");
return sb.toString();
}
sb.append(root.val+",");
sb.append(Serialize(root.left));
sb.append(Serialize(root.right));
return sb.toString();
}
TreeNode Deserialize(String str) {
index++;
int length = str.length();
if (index >= length){
return null;
}
String[] strr = str.split(",");
TreeNode node = null;
if (!strr[index].equals("#")){
node = new TreeNode(Integer.valueOf(strr[index]));
node.left = Deserialize(str);
node.right= Deserialize(str);
}
return node;
}
}
7、二叉搜索树的第k个结点
(1)问题描述:
给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
(2)解题思路:
二叉搜索树,中序遍历后可以得到一个升序序列;将升序序列存入一个栈中,pop出栈,取第k个结点返回。
(3)代码实现:
public class KthNodeInTree {
TreeNode KthNode(TreeNode pRoot, int k) {
if(pRoot==null) return null;
int i = 0;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = pRoot;
while(p!=null || stack.size()!=0){
while(p!=null){
stack.add(p);
System.out.println("p:"+ p.val);
p = p.left;
}
if(stack.size()!=0){
p = stack.pop();
if(++i==k){
return p;
}
System.out.println("p2:"+p.val);
p = p.right;
}
}
return null;
}
另:
public class Solution {
int index=0;
TreeNode KthNode(TreeNode pRoot, int k)
{
if(pRoot!=null){
TreeNode node=KthNode(pRoot.left,k);
if(node!=null)
return node;
index++;
if(index==k)
return pRoot;
node=KthNode(pRoot.right,k);
if(node!=null)
return node;
}
return null;
}
}
8、数据流中的中位数
(1)问题描述:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
(2)解题思路:
将输入数据流放进一个数组中,使用堆排序,对每个插入数据进行排序;最后返回数组的中位数;
(3)代码实现:
import java.util.Arrays;
public class Solution {
static int[] seq = new int[0];
public void Insert(Integer num) {
// int stop = list.size(), start = 0;
int stop = seq.length-1, start = 0;
if(seq.length == 0){
seq = Arrays.copyOf(seq, 1);
seq[0] = num;
}else{
while(stop >= start){
int mid = (start+stop) >>> 1;
if(seq[mid] < num){
start = mid + 1;
}else if(seq[mid] > num){
stop = mid - 1;
}else{ // key == mid
seq = Arrays.copyOf(seq, seq.length+1);
for(int i = seq.length-1;i > mid;i--){
seq[i] = seq[i-1];
}
seq[mid] = num;
break;
}
}
if(start > seq.length-1){//num bigger than last key
seq = Arrays.copyOf(seq, seq.length+1);
seq[start] = num;
}else if(stop < 0){ //num less than first key
seq = Arrays.copyOf(seq, seq.length+1);
for(int i = seq.length-1; i >0;i--){
seq[i] = seq[i-1];
}
seq[start] = num;
}else{ // num in between the seq
seq = Arrays.copyOf(seq, seq.length+1);
for(int i = seq.length-1; i > start;i--){
seq[i] = seq[i-1];
}
seq[start] = num;
}
}
}
public Double GetMedian() {
int len = seq.length;
if(len %2 ==0){
return (seq[len/2]+seq[len/2-1])/2.0;
}
return seq[len/2]*1.0;
}
}
9、滑动窗口的最大值
(1)问题描述:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1},
{2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
(2)解题思路:
循环嵌套,list
(3)代码实现:
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
int len=num.length;
ArrayList<Integer> list=new ArrayList<Integer>();
if(len==0||size<1)
return list;
for(int i=0;i<=len-size;i++){
int max=num[i];
for(int j=i+1;(j-i)<size;j++){
max=max>num[j]?max:num[j];
}
list.add(new Integer(max));
}
return list;
}
}
10、矩阵中的路径
(1)问题描述:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如 a b c e s f c s a d e e 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
(2)解题思路:
从矩阵某个外围位置开始,上下左右进行遍历查找,看是否能够匹配得到需要查找的字符串;使用回溯法上下左右进行递归尝试。
(3)代码实现:
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
int flag[] = new int[matrix.length];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (helper(matrix, rows, cols, i, j, str, 0, flag))
return true;
}
}
return false;
}
private static boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {
int index = i * cols + j;
if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1)
return false;
if(k == str.length - 1) return true;
flag[index] = 1;
if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i + 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j - 1, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) {
return true;
}
flag[index] = 0;
return false;
}
}
11、机器人的运动范围
(1)问题描述:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
(2)解题思路:
(3)代码实现:
public class Solution {
public int movingCount(int threshold, int rows, int cols) {
int flag[][] = new int[rows][cols]; //记录是否已经走过
return helper(0, 0, rows, cols, flag, threshold);
}
private int helper(int i, int j, int rows, int cols, int[][] flag, int threshold) {
if (i < 0 || i >= rows || j < 0 || j >= cols || numSum(i) + numSum(j) > threshold || flag[i][j] == 1) return 0;
flag[i][j] = 1;
return helper(i - 1, j, rows, cols, flag, threshold)
+ helper(i + 1, j, rows, cols, flag, threshold)
+ helper(i, j - 1, rows, cols, flag, threshold)
+ helper(i, j + 1, rows, cols, flag, threshold)
+ 1;
}
private int numSum(int i) {
int sum = 0;
do{
sum += i%10;
}while((i = i/10) > 0);
return sum;
}
}