面试题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;
}