面试题27_1:二叉树的镜像
遍历,若节点存在子节点,交换二叉树的左右节点;循环的方式也是和遍历一样,可以采用栈进行暂存; |
public static void MirrorRecursively(Node head){ if (head == null){ return; } if (head.left == null && head.right == null){ return; } Node temp = head.left; head.left = head.right; head.right = temp; if (head.left != null){ MirrorRecursively(head.left); } if (head.right != null){ MirrorRecursively(head.right); } } public static void Mirror(Node head){ if (head == null){ return; } Stack<Node> st = new Stack<>(); Node temp = head; while (temp != null || !st.isEmpty()){ while (temp!=null){ st.push(temp); if (temp.left != null || temp.right != null){ Node change = temp.left; temp.left = temp.right; temp.right = change; } temp = temp.left; } if (!st.empty()){ Node e = st.pop(); temp = e.right; } } }
面试题28:对称的二叉树
在原树上进行先序遍历得到的序列,和镜像上先根后右再左得到的序列应相同,且需考虑空指针; |
直接按照镜像的规则进行比较; |
public static boolean isSymmertrical(Node head){ if (head == null){ return false; } return compare(head,head); } public static boolean compare(Node head1, Node head2){ if (head1 == null && head2 == null){ return true; } if (head1 == null || head2 == null){ return false; } if (head1.value != head2.value){ return false; } return compare(head1.left,head2.right) && compare(head1.right,head2.left); }
面试题29:顺时针打印矩阵
将问题化简为循环打印圈的问题,圈的起点是有规律的(col=row);再在一圈中化简为4步,每步设定判断条件; |
public static void PrintMatrix(int[][] matrix,int rows,int cols){ if (matrix == null || rows <=0 || cols <=0){ return; } int start = 0; while (start*2<cols && start*2<rows){ PrintCircle(start,cols,rows,matrix); start++; } } public static void PrintCircle(int start,int cols,int rows,int[][] matrix){ for(int x = start;x<=cols - start -1;x++){ System.out.print(matrix[start][x]); } if (rows-start-1-start<=0){ return; } for (int x = start+1;x<= rows-start-1;x++){ System.out.print(matrix[x][cols-start-1]); } if (cols-start-1-start<=0){ return; } for (int x = cols-start-1-1;x>=start;x--){ System.out.print(matrix[rows-start-1][x]); } if (rows-start-1-start<=1){ return; } for (int x = rows-start-1-1;x>=start+1;x--){ System.out.print(matrix[x][start]); } }
面试题30:包含min函数的栈
min,push,pop的时间都是o(1),使用链栈;在查找最小值时不能使用遍历 ,也就是说需要记录下最小值;但最小值有可能随着栈的弹出而进行改变,由于无法遍历,只能在push的时候,将每步的最小值都记录下来,用栈记录,和pop保持一致,维持栈顶是最小数; |
class stack_min{ private Node head; private Node min_head; class Node{ private int data; Node next; Node(int data){ this.data = data; } } stack_min(){ head = null; min_head = null; } public void push(int value){ Node temp = new Node(value); temp.next = head; head = temp; if (min_head == null){ Node min = new Node(value); min.next = min_head; min_head = min; }else { Node min = null; if (value<min_head.data){ min = new Node(value); }else { min = new Node(min_head.data); } min.next = min_head; min_head = min; } } public int pop(){ if (head == null){ return -1; } int data = head.data; head = head.next; min_head = min_head.next; return data; } public int getmin(){ return min_head.data; } }
面试题31:栈的压入,弹出序列
设置辅助栈,按弹出序列模拟压入,若栈顶非当前元素,则在压入序列中开始扫描并压入,若有当前元素,到当前元素压入停止,若直到压入序列完依旧没找到当前元素,则失败; |
public static boolean matchstack(int[] stack_push,int[] stack_pop){ if (stack_push == null || stack_pop == null ||stack_push.length == 0 || stack_pop.length ==0 || stack_pop.length > stack_push.length){ return false; } int stack_push_index = 0; Stack<Integer> st = new Stack<>(); stack_push_index = addnew(st,stack_push,stack_pop[0],stack_push_index); if (st.peek() != stack_pop[0]){ return false; } st.pop(); for (int x = 1;x<stack_pop.length;x++){ int top = st.peek(); if (top != stack_pop[x]){ stack_push_index = addnew(st,stack_push,stack_pop[x],stack_push_index); if (st.peek() != stack_pop[x]){ return false; }else { st.pop(); } }else { st.pop(); } } return true; } public static int addnew(Stack<Integer> st,int[] stack_push,int x,int stack_push_index){ int temp = stack_push_index; while (temp < stack_push.length){ st.push(stack_push[temp]); temp++; if (stack_push[temp-1] == x){ break; } } return temp; }
面试题32_1:从上到下打印二叉树
按层次遍历,利用队列,节点出队时访问,且将其左右子树加入队列中; |
public static void Printtree(Node head){ if (head == null){ return; } ArrayDeque<Node> de = new ArrayDeque<>(); de.add(head); while (!de.isEmpty()){ Node temp = de.pollFirst(); System.out.print(temp.getData()); if (temp.left!=null){ de.add(temp.left); } if (temp.right != null){ de.add(temp.right); } } }
面试题32_2:分行从上到下打印二叉树
两个变量,一个记录本行还要打印的数目,一个记录下行需要打印的数据,本行打印完后,本行打印数目 = 下行需要打印的数目,下行打印的数目清零; |
public static void Printtree(Node head){ if (head == null){ return; } ArrayDeque<Node> de = new ArrayDeque<>(); de.add(head); int tobePrint = 1; int nextline = 0; while (tobePrint!=0){ Node temp = de.pollFirst(); System.out.print(temp.getData()); tobePrint -- ; if (temp.left != null){ de.add(temp.left); nextline ++; } if (temp.right != null){ de.add(temp.right); nextline ++; } if (tobePrint == 0){ System.out.print("\n"); tobePrint = nextline; nextline = 0; } } }
面试题32_3:之字形打印二叉树
用两个栈进行存储,将当前行与下一行进行分隔存储,根据当前行是否为奇数来判断入栈的顺序 |
public static void Print(Node root){ if (root == null){ return; } Stack<Node> st1 = new Stack<>(); Stack<Node> st2 = new Stack<>(); st1.push(root); boolean isodd = false; while (!st1.empty()){ Node temp = st1.pop(); System.out.print(temp.data); if (isodd){ if (temp.right!=null){ st2.push(temp.right); } if(temp.left != null){ st2.push(temp.left); } }else { if (temp.left!=null){ st2.push(temp.left); } if(temp.right != null){ st2.push(temp.right); } } if (st1.empty()){ isodd = !isodd; Stack<Node> st = st2; st2 = st1; st1 = st; System.out.print("\n"); } } }
面试题33_1:二叉搜索树的后序遍历序列
后序序列的最后一个元素是二叉树的根元素,由于是二叉搜索树,则根将序列可以分为两部分,一部分大于根,一部分小于根; 采用递归的办法进行判断; |
public static boolean issearchtree(int[] nums){ if (nums == null || nums.length == 0){ return false; } int lenth = nums.length; if (lenth == 1){ return true; } return issearch_core(nums,0,lenth-2,nums[lenth-1]); } public static boolean issearch_core(int[] nums,int start,int end,int data){ if (start >= end){ return true; } int index = start; for (;index<=end;index++){ if (nums[index]>data){ break; } } System.out.print(index); if (index == end+1){ return issearch_core(nums,start,end-1,nums[end]); }else { for (int x = index; x <= end; x++) { if (nums[x] < data) { return false; } } return issearch_core(nums,start,index-2,nums[index-1]) && issearch_core(nums,index,end-1,nums[end]); } }
面试题33_2:二叉搜索树的前序遍历序列
与后序序列的判断相似,只是根变为序列的第一个元素,只用改动角标 |
public static boolean issearchtree(int[] nums){ if (nums == null || nums.length == 0){ return false; } int lenth = nums.length; if (lenth == 1){ return true; } return issearch_core(nums,1,lenth-1,nums[0]); } public static boolean issearch_core(int[] nums,int start,int end,int data){ if (start >= end){ return true; } int index = start; for (;index<=end;index++){ if (nums[index]>data){ break; } } System.out.print(index); if (index == end+1){ return issearch_core(nums,start+1,end,nums[start]); }else { for (int x = index; x <= end; x++) { if (nums[x] < data) { return false; } } return issearch_core(nums,start+1,index-1,nums[start]) && issearch_core(nums,index+1,end,nums[index]); } }
面试题34:二叉树中和为某一值的路径
寻找所有路径的过程需要遍历所有的叶子节点,因为是二叉树,可以在前序遍历中完成。记录下来的路径,当遇到叶子节点时判断,若不是叶子节点则继续,在返回父节点时,从路径中删除,路径使用栈来表示; |
public static void FindPath(Node root,int expectedsum){ if (root == null){ return; } Stack<Node> st = new Stack<>(); int currentsum = 0; FindPath_core(root,expectedsum,st,currentsum); } public static void FindPath_core(Node temp,int expectedsum,Stack<Node> st,int currentsum){ currentsum += temp.data; st.push(temp); boolean isLeaf = (temp.left == null) && (temp.right == null); if (currentsum == expectedsum && isLeaf){ ArrayList<Node> ar = new ArrayList<Node>(); while (!st.empty()){ ar.add(st.pop()); } for(int x = ar.size()-1;x>=0;x--){ System.out.print(ar.get(x).data); st.push(ar.get(x)); } System.out.print("\n"); } if (temp.left != null){ FindPath_core(temp.left,expectedsum,st,currentsum); } if (temp.right != null){ FindPath_core(temp.right,expectedsum,st,currentsum); } //返回父节点之前在路径上删除该节点 st.pop(); }
面试题35:复杂链表的复制
依次复制n个并将其连接,再遍历源链表,找到每个节点的随机指针指向的节点,从头开始需要多少步,则在新链表上走同样步数可得对应节点;o(n[2]) |
依次复制n个并将其连接,同时记录下,源节点到对应节点的对应关系。o(n), o(n) |
复制,并插入在源节点后面;新的指针应指向对应的复制出的节点(源指向的后一个节点),再按奇数将链表断开成两个。o(n) |
public static Node copyComplicated(Node head){ if (head == null){ return null; } if (head.next == null){ return head; } copy(head); Link(head); return breakList(head); } public static void copy(Node head){ Node temp = head; while (temp != null){ Node newNode = new Node(temp.data); newNode.next = temp.next; temp.next = newNode; temp = newNode.next; } } public static void Link(Node head){ Node temp = head; while (temp != null){ if (temp.m_sSibling != null){ temp.next.m_sSibling = temp.m_sSibling.next; } temp = temp.next.next; } } public static Node breakList(Node head){ Node temp = head; Node newhead = new Node(-1); Node newhead_temp = newhead; while (temp != null){ newhead_temp.next = temp.next; newhead_temp = newhead_temp.next; temp.next = temp.next.next; temp = temp.next; } return newhead.next; }
面试题36:二叉搜索树和双向链表
中序遍历,处理根节点时,将其与左子树的最右节点和右子树的最左节点相连。 |
//用于共享的变量这个地方无法使用c++中的地址来做,暂时只想到申明了一个类变量来存储
static Node last; public static void main(String[] args){ Node t1 = new Node(10); Node t2 = new Node(6); Node t3 = new Node(14); Node t4 = new Node(4); Node t5 = new Node(8); Node t6 = new Node(12); Node t7 = new Node(16); t1.right= t3; t1.left = t2; t2.left = t4; t2.right = t5; t3.left = t6; t3.right = t7; Node head = turnTree(t1); print(head); } public static Node turnTree(Node root){ if (root == null){ return null; } if (root.left == null && root.right == null){ return root; } ConvertNode(root); while (last.left!=null){ last = last.left; } return last; } public static void ConvertNode(Node head){ if (head == null){ return; } if (head.left != null){ ConvertNode(head.left); } head.left = last; if (last != null){ last.right = head; } last = head; if (head.right != null){ ConvertNode(head.right); } }
面试题37:序列化二叉树
采用前序+中序的方式表示树会无法还原有相同节点的树,所以只能采用加上特殊字符表示空的序列来进行表示,还原的过程与序列化的过程相对应。 |
public static Node turnArraytoTree(ArrayList<String> ar){ if (ar == null || ar.size() == 0){ return null; } String num = ar.remove(0); if (num == "$"){ return null; } Node nex = new Node(Integer.parseInt(num)); nex.left = turnArraytoTree(ar); nex.right = turnArraytoTree(ar); return nex; } public static ArrayList<String> turnTreetoArray(Node root){ ArrayList<String> ar = new ArrayList<>(); if (root ==null){ return ar; } turnTreetoArray_core(root,ar); return ar; } public static void turnTreetoArray_core(Node temp,ArrayList<String> ar){ if (temp == null){ ar.add("$"); return; } ar.add(temp.data+""); turnTreetoArray_core(temp.left,ar); turnTreetoArray_core(temp.right,ar); }
面试题38_1:字符串的排列
将字符串看为两个部分,首字符和剩余,第一层循环用于将首字符与剩余的进行交换,第二层则递归的将剩余的字符也看做两部分; |
public static void Permutation(char[] test){ if (test == null || test.length == 0){ return ; } Permutation_core(test,0); } public static void Permutation_core(char[] test,int first){ if (first == test.length-1){ for (char x:test){ System.out.print(x); } System.out.println("\n"); } else { for (int x = first;x<test.length;x++){ char temp = test[x]; test[x] = test[first]; test[first] = temp; Permutation_core(test,first+1); temp = test[x]; test[x] = test[first]; test[first] = temp; } } }
面试题38_2:求输入字符的组合
求n个数长度为m的组合 = 剩下的n-1个数中选择m-1个 + 剩下的n-1个数中选择m个(当剩下的还有>=m个时) 输入的n个字符可以构成1,2...n的组合; |
public static void getZuhe(char[] chars){ if (chars == null || chars.length == 0){ return; } if (chars.length == 1){ System.out.print(chars[0]); return; } String temp = ""; for (int x = 1;x<= chars.length;x++){ getZuhe_core(chars,0,x,temp); } } public static void getZuhe_core(char[] chars, int first, int num,String temp){ if (num == 0){ System.out.println(temp); return; } if (chars.length-1-first >= num-1) { getZuhe_core(chars, first + 1, num - 1, temp + chars[first]); } if (chars.length-1-first >= num){ getZuhe_core(chars,first+1,num,temp); } }
面试题38_3:把8个数字放在正方形的8个顶点上
求8个数字的所有排列,判断排列是否满足3组求和条件,存在满足的情况则存在; |
public static boolean getPailie(int[] nums){ if ( nums == null || nums.length != 8){ return false; } return getPailie_core(nums,0); } public static boolean getPailie_core(int[] nums , int first){ if (first == nums.length -1){ return judge(nums); } for (int x = first;x<=nums.length-1;x++){ int temp = nums[x]; nums[x] = nums[first]; nums[first] = temp; boolean index = getPailie_core(nums,first+1); if (index == true){ return true; } temp = nums[x]; nums[x] = nums[first]; nums[first] = temp; } return false; } public static boolean judge(int[] nums){ if (nums[0]+nums[1]+nums[2]+nums[3] == nums[4]+nums[5]+nums[6]+nums[7] && nums[0]+nums[2]+nums[4]+nums[6] == nums[1]+nums[3]+nums[5]+nums[7] && nums[0] +nums[1]+nums[4]+nums[5] == nums[2] +nums[3]+nums[6]+nums[7]){ return true; }else { return false; } }
面试题38_4:8皇后问题
8位皇后占8行,再用一个8位的数组分别表示每行的皇后在第几列,用0-7初始化保证列不相同,求出数组的排列,再判断在此排列下,是否会有两个皇后在同一对角线上。同一对角线的行之差 = 列之差; |
//递归中可以选择3种方式传递参数,1.设全局变量 2.利用函数返回值更新 3.设局部变量,不断累加或更改;
public static int getPailie(){ int[] nums = {0,1,2,3,4,5,6,7}; return getPailie_core(nums,0); // return count; } public static int getPailie_core(int[] nums , int first){ int count = 0; if (first == nums.length -1){ if (judge(nums) == true){ count += 1; } return count; } for (int x = first;x<=nums.length-1;x++){ int temp = nums[x]; nums[x] = nums[first]; nums[first] = temp; count += getPailie_core(nums,first+1); temp = nums[x]; nums[x] = nums[first]; nums[first] = temp; } return count; } public static boolean judge(int[] nums){ for (int x = 0; x< nums.length -1;x++){ for (int y = x+1;y <= nums.length -1 ;y++){ if ( Math.abs(y-x) == Math.abs(nums[y]-nums[x])){ return false; } } } return true; }