面试相关高频算法考点4

目录

  • 一、求二叉树深度
  • 二、异或理解,求数组中只出现一次的两个数
  • 三、滑动窗口,求和为S的连续正数序列
  • 四、左旋旋转字符串
  • 五、翻转单词序列,子串划分
  • 六、按照之字形顺序打印二叉树
  • 七、找出BST(二叉搜索树)中第K小的节点

一、求二叉树深度

牛客链接
描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度,根节点的深度视为 1 。

方法一:使用递归方式
分别遍历根的左和根的右,然后取两边中较大的一边,最后再加上有根节点的那一层就是整棵树的深度。

public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        int leftTree = TreeDepth(root.left);
        int rightTree = TreeDepth(root.right);
        return (leftTree > rightTree) ? leftTree + 1 : rightTree + 1;
    }
}

方法二:分别遍历左子树高度和右子树高度,然后取两边最大值即可。

public class Solution {
    public int max = 0;
    public void TreeNodeHelper(TreeNode root,int cur){
        if(root == null){
            
            if(max < cur){
                max = cur;
            }
            return;
        }
        TreeNodeHelper(root.left,cur + 1);
        TreeNodeHelper(root.right,cur + 1);
    }
    public int TreeDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
        int depth = 0;
        TreeNodeHelper(root,depth);
        return max;
    }
 }        

方法三:层序遍历。利用二叉树的层序遍历,遍历完一层之后,深度加1,直到遍历完整颗二叉树。

public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null){
            return 0;
        }
         Queue<TreeNode> queue = new LinkedList<>();
         queue.offer(root);
             int depth = 0;
         while(!queue.isEmpty()){
             int size = queue.size();
                 depth++;
             while(size != 0){
                 TreeNode cur = queue.poll();
                 if(cur.left != null){
                     queue.offer(cur.left);
                 }
                 if(cur.right != null){
                     queue.offer(cur.right);
                 }
                 size--;
             }
         }
         return depth;
      }
   }

二、异或理解,求数组中只出现一次的两个数

牛客链接
描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
解题思路:先将整个数组进行异或,得到那两个只出现一次数字进行以异或的结果,然后将该数字与1进行一位与运算,得到这两个数字第一次出现不同的位置,以该位置为标志位重新对整个数组进行遍历,数组中的每个元素都与其进行与运算,得到两字不用的结果,其结果就是该数组中只出现一次的两个数字。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        if(array == null || num1 == null || num2 == null){
            return;
        }
        int res = array[0];
        num1[0] = 0;
         num2[0] = 0;
        //得到的是两个不同的数进行异或的结果,因为相同的两个数进行异或结果为0
        for(int i = 1;i < array.length;i++){
            res ^= array[i];
        }
        int len = Integer.SIZE;//得到int类型有多少个比特位
        int flg = 1;
        while(len >= 0){
            len --;
            //找到两位不同的数异或得到的数中第一个为1的位置,并记录在flg中
            if(((flg << len) & res) != 0){
                flg = flg << len;
                break;
            }
        }
        //以标志位为基准,遍历数组,得到只出现一次的两个数字
        for(int i = 0;i < array.length;i++){
            if((flg & array[i]) == 0){
                num1[0] ^= array[i];
            }else{
                num2[0] ^= array[i];
            }
        }
    }
}

三、滑动窗口,求和为S的连续正数序列

牛客链接
描述:
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
返回值描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序。
解题思路:
不考虑负数情况,定义两个位置,表示起始和结束,start和end之间就是一段连续递增的序列;这两个位置,相当于动态窗口的两边,根据其窗口内的值的和来确定窗口的位置和大小。我们采用闭区间方式进行解决。

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
       
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if(sum == 0){
            return res;
        }
        //分别用left和right标记连续序列的前两个数
        int left = 1;
        int right = 2;
        while(left < right){
            //连续序列求和公式,属于闭区间
            int total = (left + right) * (right - left + 1) / 2;
            if(total == sum){
                ArrayList<Integer> list = new ArrayList<>();
                for(int i = left;i <= right;i++){
                    list.add(i);
                }
                res.add(list);
                //从保存序列的下一位left重新开始遍历
                left++;
            }else if(total < sum){
                //说明该序列区间中的数据和小于sum,应该扩大区间,以包含更多数据
                right++;
            }else{
                //说明该序列区间中的数据和大于sum,应该缩小区间,以包含较少数据
                left++;
            }
        }
        return res;
    }
}

四、左旋旋转字符串

牛客链接
描述:
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列 S ,请你把其循环左移 K 位后的序列输出。例如,字符序列 S = ”abcXYZdef” , 要求输出循环左移 3 位后的结果,即 “XYZdefabc” 。是不是很简单?OK,搞定它!
方法一:字符串座左移1位的方法就是,取出字符串中的第一个元素,然后将后面的元素挨个往前移动一位,再把取出的第一位元素放到最后一位即可。然后需要左移几位,就循环调用几次即可。

public class Solution {
    public void LeftRotateStringHelper(char[] str){
        char tmp = str[0];
        int i = 0;
        for( i = 0; i < str.length - 1;i++){
            str[i] = str[i + 1];
        }
        str[i] = tmp;
    }
    public String LeftRotateString(String str,int n) {
        if(str.length() == 0 || n ==0){
               return str;
        }
        //将字符串转换为字符数组
        char[] s = str.toCharArray();
        //如果n过大,则很多左移是重复的,可以在这对其求余
        n %= str.length();
        while(n > 0){
            LeftRotateStringHelper(s);
            n--;
        }
        return new String(s);
    }
}

方法二:先逆置字符串的前n个,再逆置剩下的字符串。然后再整体进行逆置同样可以达到左旋n个字符串的效果。
如:abcXYZdef 字符串需要左旋三位得到XYZdefabc,我们就可以:
1.逆置前三位:cba
2.逆置字符串剩下的元素:fedZYX,此事得到的字符串就是:cbafedZYX
3.再对2得到的字符串进行整体逆置:XYZdefabc

public class Solution {
    //字符串逆置
    public void Rverse(char[] s,int start,int end){
        while(start < end){
            char tmp = s[start];
            s[start] = s[end];
            s[end] = tmp;
            start++;
            end--;
        }
    }
    public String LeftRotateString(String str,int n) {
       if(str.length() == 0 || n == 0){
           return str;
       }
        n %= str.length();
        char[] s = str.toCharArray();
        Rverse(s,0,n - 1);
        Rverse(s,n,s.length - 1);
        Rverse(s,0,s.length - 1);
    	return new String(s);
  }
}

五、翻转单词序列,子串划分

牛客链接
描述:
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
**解题思路:**先局部逆置,再整体逆置。
首先遍历数组,直到遇到空格就说明此时将一个单词遍历完毕,对这个单词进行逆置操作,以此方式遍历、逆置完整个数组,最后再将整个数组进行逆置即可。
如:“nowcoder. a am I”

  1. .redocwon
  2. a
  3. ma
  4. I
  5. 此时得到: .redocwon a ma I,然后对其整体进行逆置得:I am a nowcoder.
public class Solution {
    public void Reverse(char[] s,int start,int end){
        while(start < end){
            char tmp = s[start];
            s[start] = s[end];
            s[end] = tmp;
            start++;
            end--;
        }
    }
    public String ReverseSentence(String str) {
        if(str == null || str.length() == 0){
            return str;
        }
        int i = 0;
        int j = i;
        //将字符串转换为字符数组
        char[] list = str.toCharArray();
        int len = list.length;
        while(i < len){
            //遍历字符数组,直到遇到第一个空格
            while(i < len && !Character.isSpace(list[i])) {
                i++;
            }
            Reverse(list,j,i - 1);
            //再次遍历,避免出现两个空格的情况
            //过滤所有空格,指向下一个有效子串的开始
            while(i < len && Character.isSpace(list[i])){
                i++;
            } 
            
            //保存起始位置
            j = i;
        }
        //此时i指向的是最后一个单词的最后位置,它还未进行翻转,
        //这里需要将最后一个单词翻转
        Reverse(list, j, i-1);
        Reverse(list, 0, i-1);
        return new String(list);
    }
}

六、按照之字形顺序打印二叉树

牛客链接
描述:
给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)。
解题思路:
之字形打印,本质也是对树形结构的层序遍历,不过在遍历的过程中,需要更改遍历顺序,可以采用stackqueue的方式来进行处理。当前层从左向右遍历,那么下层就从left到right入栈,当前层如果从右向左遍历,那么下层就从right到
left入栈。
根据栈先进后出的思想来对二叉树进行层序遍历

import java.util.*;
/*
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>>  res = new ArrayList<>();
        if(pRoot == null){
            return res;
        }
        //保存要遍历的节点
        Stack<TreeNode> stack = new Stack<>();
        //作为临时队列来进行辅助
        Queue<TreeNode> queue = new LinkedList<>();
        ArrayList<Integer> list = new ArrayList<>();
        stack.push(pRoot);
        int flg = 1;//1表示从左向右,2表示从右向左
        while(!stack.isEmpty()){
            int size = stack.size();
            //清空本轮stack结构,并遍历,stack本身有逆序的功能
            for(int i = 0;i < size;i++){
                TreeNode cur = stack.pop();
                list.add(cur.val);
                TreeNode first = (flg == 1) ? cur.left : cur.right;
                TreeNode sceond = (flg== 1) ? cur.right : cur.left;
                //将下一轮访问顺序放入q中
                if(first != null){
                    queue.offer(first);
                }
                if(sceond != null){
                    queue.offer(sceond);
                }
            }
            res.add(new ArrayList(list));//浅拷贝
            list.clear();
            //将下一轮访问节点入栈,进行逆序
            while(!queue.isEmpty()){
                stack.push(queue.poll());
            }
            //一层遍历完之后,改变入栈顺序
           flg = (flg == 1) ? 2 : 1;
        }
        return res;
    }
}

七、找出BST(二叉搜索树)中第K小的节点

牛客链接
给定一棵二叉搜索树,请找出其中的第k小的结点。例如,(5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
解题思路BST本身就是有序的,中序遍历即是升序;要求第k小,即中序遍历时到达第k个元素(二叉搜索树,不存在两个相同的节点值),此处,我们采用循环中序遍历的方式。

import java.util.Stack;
//BST本身就是有序的,中序遍历即是升序
//要求第k小,即中序遍历时到达第k个元素(二叉搜索树,不存在两个相同的节点值)
//此处,我们不使用递归,我们采用循环中序遍历的方式
public class Solution {
TreeNode KthNode(TreeNode pRoot, int k){
	if(pRoot == null || k <= 0){
		return null;
	} 
Stack<TreeNode> st = new Stack<>();
TreeNode node = pRoot;
do{
	while(node != null){
		st.push(node);
		node = node.left;
	} 
	if(!st.empty()){
		node = st.pop();
	//访问当前节点,中序
		k--;
	if(k == 0){
		return node;//找到当前第k小节点
	} 
		node = node.right;
	}
}while(node != null || !st.empty()); 
//node有可能为空,但是只要stack不为空,就要继续pop求下一个。
//有没有可能st为空?有可能,这个时候就要检测node,如果node不为空,就要整体检测右子树
//走到这里,就说明没有找到
	return null;
	}
}

以上。

你可能感兴趣的:(JAVA,数据结构,编程,算法,面试,职场和发展,java,数据结构)