剑指Offer系列之题56~题60
56.删除链表中重复的结点 🔺
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
添加头结点,作为辅助,便于剔除第一个和第二节点就相等的情况;
递归。都需要考虑开头就出现两节点相等的情况。
1.添加头结点:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null || pHead.next==null){
return pHead;
}
//可能存在多个相同
ListNode head=new ListNode(0);//头结点
head.next=pHead;
ListNode pre=head;
ListNode last=head.next;//从第一个结点开始
while(last!=null){
if(last.next!=null && last.val==last.next.val){
//循环直到last.next为空或者找到不重复结点
while(last.next!=null && last.val==last.next.val)
last=last.next;
pre.next=last.next;//last.next为空则直接链接null,否则链接不重复结点
last=last.next;
}else{
pre=pre.next;//不等时,前结点后移
last=last.next;
}
}
return head.next;
}
}
2.递归:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null || pHead.next==null){
return pHead;
}
//两个循环,用来应付“1-1-2-2-3-3-4-5…”格式的连续重复结点
while(pHead != null && pHead.next != null && pHead.val == pHead.next.val){
while(pHead != null && pHead.next != null && pHead.val == pHead.next.val){
pHead = pHead.next;
}//找到当前与下一节点不等的结点
pHead = pHead.next;//将该节点右移
}
if(pHead!=null ){
pHead.next = deleteDuplication(pHead.next);
}
return pHead;
}
}
57.二叉树的下一结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
判断该节点右子树是否为空,非空则返回右子树的最左子节点;
判断父节点是否空,非空则判断该节点是父节点的左或右子树,左子树则返回父节点,右子树则从父结点开始找到是父节点左子节点的结点,返回该节点的父节点
1.:
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
//中序:左 根 右
//不仅包含左右子结点,同时包含指向父结点的指针。
if(pNode==null)
return null;
TreeLinkNode next=null;
if(pNode.right!=null){//找到右子树的最左子节点
TreeLinkNode temp=pNode.right;
while(temp!=null){
if(temp.left==null){
next=temp;
break;
}else{
temp=temp.left;
}
}
}else if(pNode.next!=null){//父节点非空
//判断该节点是父节点的左或右子树
TreeLinkNode father=pNode.next;//找到其父节点
if(father.left==pNode)
return father;//如果是父节点的左子树,则返回父节点
//若是父节点的右子树,则沿着其父节点向上找到 是它父节点左子节点的结点,则其父节点是下个结点
if(father.right==pNode){
while(father.next!=null){
if(father==father.next.left){
next=father.next;;
break;
}
father=father.next;
}
}
}
return next;
}
}
58.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
递归:前序(根左右)遍历和根右左遍历序列相等时,二叉树对称;
非递归:利用栈或队列成对存储元素,成对取出比较。
1.递归:
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
//前序遍历和 根右左遍历序列相等则对称
return helper(pRoot,pRoot);
}
//遍历的节点 root1前序遍历 root2根左右顺序遍历
boolean helper(TreeNode root1,TreeNode root2){
if(root1==null && root2==null)//两节点都为空则true
return true;
if(root1==null || root2==null)//两节点只有一个为空,false
return false;
if(root1.val!=root2.val)//两节点值不等,false
return false;
return helper(root1.left,root2.right) && helper(root1.right,root2.left);
}
}
2.非递归:
栈如下;队列同理,代码相似。不过前者是DFS,后者是BFS
import java.util.Stack;
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
if(pRoot==null)
return true;
//栈成对 存储 取出节点
Stack<TreeNode> stack=new Stack<>();
stack.push(pRoot.left);
stack.push(pRoot.right);
while(!stack.empty()){
TreeNode right=stack.pop();
TreeNode left=stack.pop();
if(left ==null && right==null)
continue;
if(left ==null || right==null)
return false;
if(left.val!=right.val)
return false;
//入四个,下次出两个,会先进行到叶节点,然后再向上返回遍历其他节点。->深度优先
stack.push(left.left);
stack.push(right.right);
stack.push(left.right);
stack.push(right.left);
}
return true;
}
}
59.按之字形顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
辅助栈存储奇数偶数层的结点,然后输出。因为从左到右,从右到左,栈符合该特点;
或者使用双端队列
1. 辅助栈:
import java.util.ArrayList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
import java.util.Stack;
public class Solution {
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
ArrayList<ArrayList<Integer>> resList=new ArrayList<>();
if(pRoot==null)
return resList;
int depth=0;//层数,当奇数从左到右,偶数从右到左
Stack<TreeNode> stack1=new Stack<>();//奇数层栈
Stack<TreeNode> stack2=new Stack<>();//偶数层栈
stack1.push(pRoot);
TreeNode temp=null;
while(!stack1.empty() || !stack2.empty()){
depth++;//当前层
ArrayList<Integer> res=new ArrayList<>();
if(depth%2!=0){//奇数层
while(!stack1.empty()){
temp=stack1.pop();
res.add(temp.val);
//下一层从左到右入
if(temp.left!=null)
stack2.push(temp.left);
if(temp.right!=null)
stack2.push(temp.right);
}
}else{//偶数层
while(!stack2.empty()){
temp=stack2.pop();
res.add(temp.val);
//下一层从右到左入
if(temp.right!=null)
stack1.push(temp.right);
if(temp.left!=null)
stack1.push(temp.left);
}
}
resList.add(res);
}
return resList;
}
}
60.把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
层次遍历,利用辅助队列
1.队列;
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
//层次遍历
ArrayList<ArrayList<Integer>> resList=new ArrayList<>();
if(pRoot==null)
return resList;
Queue<TreeNode> queue=new LinkedList<>();
int width=0;//宽度,当前层结点个数
int count=0;//当前层已遍历结点数
TreeNode temp=null;//存储遍历的结点
queue.offer(pRoot);
while(!queue.isEmpty()){
width=queue.size();
ArrayList<Integer> res=new ArrayList<>();
while(count<width){//遍历当前层
temp=queue.poll();
count++;
res.add(temp.val);
if(temp.left!=null)
queue.offer(temp.left);
if(temp.right!=null)
queue.offer(temp.right);
}
count=0;
resList.add(res);
}
return resList;
}
}
2.递归:
public class Solution {
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
//层次遍历
ArrayList<ArrayList<Integer>> resList=new ArrayList<>();
helper(pRoot,1,resList);//结点,结点所在层数,结果列表
return resList;
}
public void helper(TreeNode root,int depth,ArrayList<ArrayList<Integer>> resList){
if(root==null)//结点空则返回
return;
if(depth>resList.size())//若深度大于列表大小,说明该结点所在行还未记录
resList.add(new ArrayList<Integer>());//添加一行
resList.get(depth-1).add(root.val);//将当前节点的值添加到列表内的最后一行
helper(root.left,depth+1,resList);//左右子树均在下一行进行遍历
helper(root.right,depth+1,resList);
}
}
如有错误,欢迎指正