面试中遇到的手撕代码题(一)

1.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

根据二叉树的性质:
这里写图片描述

public class Rebuild_Tree {

    public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        // 从头开始重建
        TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, in, 0,
                in.length - 1);
        return root;
    }

    public TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre,
            int[] in, int startIn, int endIn) {
        if (startPre > endPre || startIn > endIn)// 表示已经构建好了
            return null;
        TreeNode node = new TreeNode(pre[startPre]);// 前序遍历第一个就是根节点了
        for (int i = 0; i < in.length; i++) {
            if (pre[startPre] == in[i]) {
                node.left = reConstructBinaryTree(pre, startPre + 1, startPre
                        + i - startIn, in, startIn, i - 1);
                node.right = reConstructBinaryTree(pre, startPre + i - startIn
                        + 1, endPre, in, i + 1, endIn);
            }
        }
        return node;
    }
}

2.旋转数组的最小数字

需要考虑三种情况:
(1)array[mid] > array[high]:
出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1
(2)array[mid] == array[high]:
出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边还是右边,这时只好一个一个试 ,high = high - 1
(3)array[mid] < array[high]:
出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
边。因为右边必然都是递增的。
(4)当剩下两个数据的时候,那么最小值就是小的那一个树。

public class Rotate_Min {

    public static int minNumberInRotateArray(int[] array) {
        if(array.length==1) return array[0];
        int low = 0, high = array.length - 1, mid;
        int min = 0;
        while (low < high) {
            if (low + 1 == high)// 只剩下一个的时候target肯定是最小的哪一个
                min = Math.min(array[low], array[high]);
            mid = (low + high) / 2;
            if (array[mid] > array[high])
                low = mid + 1;
            if (array[mid] < array[high])
                high = mid;// 注意,这里不是mid-1.
            else {
                high = high - 1;
            }
        }
        return min;
    }
}

3.给一个数组返回最小堆或者最大堆

先来看看数据结构
这里写图片描述

然后大顶堆用数组表示如下:
这里写图片描述

我们用简单的公式来描述一下堆的定义就是:
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]

public class Max_Heap {

    public static int[] maxHeap(int[] array) {
        // 1.构建大顶堆
        for (int i = array.length / 2 - 1; i >= 0; i--) {
            // 从第一个非叶子结点从下至上,从右至左调整结构
            adjustHeap(array, i, array.length);
        }
        return array;
    }

    private static void adjustHeap(int[] array, int i, int length) {
        int parent = array[i];
        for (int k = 2 * i + 1; k < length; k = k * 2 + 1) {
            // 2*i+1表示左节点,k = k * 2 + 1表示继续调整子节点
            if (k + 1 < length && array[k] < array[k + 1])
                k = k + 1;// 找到子节点中更大的节点
            if (array[k] > parent) {
                array[i] = array[k];// 父节点变为更大的值
                i = k;// 修改i的值,使之成为新的要调整的父节点
            } else {
                break;// 表示无需调整,因为是自底向上的
            }
        }
        array[i] = parent;// 将temp值放到最终的位置
    }

    public static void main(String[] args) {
        int[] array = { 4, 6, 8, 5, 9 };
        int[] maxHeap = maxHeap(array);
        for (int i : maxHeap) {
            System.out.print(i + " ");
        }
    }
}

那么手写堆排序你会不会?

public static void sort(int []arr){
        //1.构建大顶堆
        for(int i=arr.length/2-1;i>=0;i--){
            adjustHeap(arr,i,arr.length);
        }
        //2.调整堆结构+交换堆顶元素与末尾元素
        for(int j=arr.length-1;j>0;j--){
            swap(arr,0,j);//将堆顶元素与末尾元素进行交换
            adjustHeap(arr,0,j);//重新对堆进行调整
        }

    }

4.最大公约数非递归算法

求a、b两个数的最大公约数。

if(a < b){
        temp = a;
        a = b;
        b = temp;

    }
    while(a%b != 0){
            temp = a%b;
            a = b;
            b = temp;
    }
    return b;

5.二维平面有n个点,求一条直线,使最多的点落在该直线上

可以根据A点跟其他点所构成线段的斜率判断与A点共线的点的个数.遍历所有点,取出最大值即可,
1.考虑重复点的情况.
2.考虑斜率为无穷大的情况.

import java.util.HashMap;

//定义座标点

class Point {
    int x;
    int y;
    Point() { x = 0; y = 0; }
    Point(int a, int b) { x = a; y = b; }
}

public class Solution {
//判断座标点集是否为空
    public int maxPoints(Point[] points) {
        if(points==null||points.length==0){
            return 0;
        }
//建立Hash表
        HashMap<Double,Integer> map= new HashMap<Double,Integer>();
        int max=1;
        for(int i=0;i<points.length;i++){
            map.clear();       //每次重设A点时,清空Hash表
            map.put((double)Integer.MIN_VALUE,1);//斜率—点数
            int dup=0;
            for(int j=i+1;j<points.length;j++){
            //判断点是否重合
                if(points[j].x==points[i].x&&points[j].y==points[i].y){
                    dup++;
                    continue;
                }
            //判断斜率的K值.
                double key=points[j].x-points[i].x==0?
                        Integer.MAX_VALUE:
                            0.0+(double)(points[j].y-points[i].y)/(double)(points[j].x-points[i].x);
                if(map.containsKey(key)){
                    map.put(key,map.get(key)+1);
                }else{
                    map.put(key, 2);
                }
            }
            for(int temp:map.values()){
                if(temp+dup>max){
                    max=temp+dup;
                }
            }
        }
        return max;
    }
}

6.两数之和

题目的意思:给定任意一个数组,和一个固定值,要求你在数组中找出满足a+b = target的情况,并返回这两个值的索引。

Example:

Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
比较简单,我们只需要借助一个HashMap即可
其中key=target-nums[i],value=数组的下标

import java.util.HashMap;
import java.util.Map;
public class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] result = new int[2];
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < numbers.length; i++) {
            if(map.containsKey(numbers[i])){
                result[0] = map.get(numbers[i])+1;
                result[1] = i+1;
            }else {
                map.put(target-numbers[i], i);
            }
        }
        return result;
    }
}

7.三个数之和

这里我们可以借鉴两数之和的思想,将三数之和看成两之和与一个target。

public class Three_Sum {

    public static Set<ArrayList<Integer>> threeSum(int[] num) {
        Arrays.sort(num);
        Set<ArrayList<Integer>> result = new HashSet<>();
        for (int i = 0; i < num.length; i++) {
            //target = target-num[i]
            twoSum(num, i, target - num[i], result);
        }
        return result;
    }
    //两数之和的方法
    public static void twoSum(int[] numbers, int start,
            int target, Set<ArrayList<Integer>> result) {
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = start + 1; i < numbers.length; i++) {
            if (map.containsKey(numbers[i])) {
                ArrayList<Integer> round = new ArrayList<Integer>();
                round.add(numbers[start]);
                round.add(numbers[map.get(numbers[i])]);
                round.add(numbers[i]);
                result.add(round);
            }
            map.put(target-numbers[i], i);
        }
    }

    public static void main(String[] args) {
        int[] nums = {-1,0,1,2,-1,-4};
        Set<ArrayList<Integer>> threeSum = threeSum(nums);
        for (ArrayList<Integer> arrayList : threeSum) {
            for (Integer integer : arrayList) {
                System.out.print(integer+",");
            }
            System.out.println();
        }
    }
}

ps:第一部分先写到这里

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章