android面试笔记总结(算法篇)

Android面试总结(算法篇)

快速排序

  • 每次取一个基准值,然后每次从基准值左边和右边取值,找到基准值左边比基准值大或等于的值,找到基准值右边比基准值小或等于的值,然后左边和右边的值进行交换
  • 完成上面一趟交换后,基准值左边的再进行循环比较,基准值右边的再循环比较
/**
 * 快速排序
 *
 * @param arr
 * @param L   指向数组第一个元素
 * @param R   指向数组最后一个元素
 */
public static void quickSort(int[] arr, int L, int R) {
    int i = L;
    int j = R;
    //支点以数组的中间的数为准
    int pivot = arr[(L + R) / 2];
    //左右两端进行扫描,只要两端还没有交替,就一直扫描
    while (i <= j) {
        //在左边找比支点大的数
        while (pivot > arr[i])
            i++;
        //在右边找比支点小的数
        while (pivot < arr[j])
            j--;
        //此时已经分别找到了比支点小的数(右边)、比支点大的数(左边),它们进行交换
        if (i <= j) {
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
            i++;
            j--;
        }
        for (int m = 0; m < arr.length; m++) {
            System.out.print(" " + arr[m]);
        }
        System.out.println("");
    }
    //上面一个while保证了第一趟排序支点的左边比支点小,支点的右边比支点大了。
    //“左边”再做排序,直到左边剩下一个数(递归出口)
    if (L < j)
        quickSort(arr, L, j);
    //“右边”再做排序,直到右边剩下一个数(递归出口)
    if (i < R)
        quickSort(arr, i, R);
}

插入排序

//插入排序
public void insertSort(int[] array) {
    for (int i = 1; i < array.length; i++) {
        int temp = array[i];//当前的值
        int j = i - 1;//定位到当前索引的前一个
        while (j >= 0 && temp < array[j]) {
            //前面的数比当前值要大,则将前面的值替换给当前值
            array[j + 1] = array[j];
            //位置向前进一位
            j--;
        }
        //将当前值放到最前面的索引
        array[j + 1] = temp;
    }
}

选择排序

  • 第一层循环表示前面的数,后面一层循环表示后面的数
  • 而冒泡排序的第一层循环表示每一轮循环的次数
public static void order() {
    int[] a = {3, 0, 1, 2, 11, 7};
    for (int i = 0; i < a.length - 1; i++) {
        for (int j = i; j < a.length; j++) {
            int temp;
            if (a[i] > a[j]) {
                temp = a[j];
                a[j] = a[i];
                a[i] = temp;
            }
        }
    }
    for (int i = 0; i < a.length; i++) {
        System.out.println("result:" + a[i]);
    }
}

冒泡排序

  • 跟选择排序的不同地方是第一层循环表示每一轮循环的次数
public static void sort() {
    int[] a = {3, 0, 1, 2, 11, 7};
    for (int i = 1; i < a.length; i++) {
        for (int j = 0; j < a.length - i; j++) {
            if (a[j] > a[j + 1]) {
                int temp = a[j + 1];
                a[j + 1] = a[j];
                a[j] = temp;
            }
        }
    }
    for (int i = 0; i < a.length; i++) {
        System.out.println("result:" + a[i]);
    }
}

二分法查找

  • 排序好的数组,找出对应数的位置,没找到的话返回-1
//二分法查找
public  int erfenfa(int[] array, int find) {
    int min = 0;
    int max = array.length - 1;
    int result = -1;
    while (min <= max) {
        int temp = (max + min) / 2;
        //如果要找的数比中间值小,则将最大的索引向左移一位
        //,否则将最小的索引向右移一位
        if (find < array[temp]) {
            max = temp - 1;
        } else if (find > array[temp]) {
            min = temp + 1;
        } else {
            result = temp;
            break;
        }
    }
    return result;
}

两个栈实现队列

  • 栈的规则是先进后出,后进先出,队列是先进先出,后进后出
public class StackQueue {
    Stack stack1 = new Stack();
    Stack stack2 = new Stack();
    public void push(int node){
        //实现队列的push直接将元素放到第一个栈中
        stack1.push(node);
    }
    public int pop(){
        //如果第2个栈是空的,需要将第一个栈的数据依次取出来
        if(stack2.empty()){
            //直到第一个栈中的数据取完了
            while(!stack1.empty())
                stack2.push(stack1.pop());
        }
        return stack2.pop();
    }
}

链表常见题

  • 常见题型有链表翻转、求倒数第k个节点、判断是不是环形链表、链表部分翻转、链表合并、链表排序等。
  • 链表有一个next指向下一个指针,如果next=null说明到了链表的结束位置,环链表除外,后面题型会涉及到环形链表
public static class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}

翻转链表

//链表翻转,思想是定义一个节点,然后节点的pre指向了节点的next
//1->2->3->4->5
//5->4->3->2->1
public  ListNode revertListNode(ListNode listNode) {
    ListNode preNode = null;
    ListNode nextNode;
    while (listNode != null) {
        //先取出next,后面放到listNode的时候用
        nextNode = listNode.next;
        //preNode指向next节点
        listNode.next = preNode;
        //将当前节点给到pre,下次判断节点的时候用得到
        preNode = listNode;
        listNode = nextNode;
    }
    return preNode;
}

求链表中倒数第k个结点

/**
 * 输入一个链表,输出该链表中倒数第k个结点。
 *
 * @param head
 * @param k
 * @return
 */
public static ListNode FindKthToTail(ListNode head, int k) {
    ListNode second = head;
    ListNode first = head;
    //双指针的思想,让第一个指针先走,走到第k个结点后,第二个指针也跟着走,
    // 当第一个节点走到最后的时候,第二个节点位置就是倒数第k个结点的位置
    for (int i = 0; i < k; i++) {
        first = first.next;
    }
    while (first != null) {
        first = first.next;
        second = second.next;
    }
    return second;
}

判断一个链表是否有环

/**
 * 判断一个链表是不是环形链表
 * 定义个块的指针和慢的指针,如果两个再次相遇说明是环形链表
 * @param head
 * @return
 */
private boolean isLoop(ListNode head) {
    //定义快慢指针
    ListNode fast = head.next;
    ListNode slow = head.next;
    while(fast != null && slow != null && fast.next != null) {
            //快指针每次走两步,慢指针每次走一步
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                //如果再次相遇,则说明有环,返回true
                return true;
            }
        }
    }
    return false;
}

每k位进行翻转链表

  • 每k位翻转链表是在整个链表翻转的基础上演变而来的,它是先将链表分成每k个来进行翻转,然后将当前翻转的结果给上一次翻转结果的最后一个指针
public static ListNode reverse(ListNode head, int k) {
    ListNode current = head;
    ListNode next = null;
    ListNode prev = null;
    int count = 0;
     //翻转的条件
    while (current != null && count < k) {
        next = current.next;
        current.next = prev;
        prev = current;
        current = next;
        count++;
    }
    //如果后面还有元素,则递归翻转
    if (next != null) {
          //将下一次翻转的结果给当前最后一个元素的next位置
        head.next = reverse(next, k);
    }
    return prev;
}

二叉树常见题

  • 二叉树常见题型有二叉树深度计算、二叉树的镜像二叉树、根据二叉树的前序遍历、和中序遍历顺序求出二叉树结构。
  • 二叉树有一个左子节点和右子节点。
public static class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) {
        val = x;
    }
}

求二叉树的深度

public static int TreeDepth(TreeNode root) {
    //如果当前节点为空,说明已经到底了
    if (root == null)
        return 0;
    //递归调用深度左右子树的深度
    int left = TreeDepth(root.left);
    int right = TreeDepth(root.right);
    //取左右子树大的深度值
    return left > right ? left + 1 : right + 1;//每次将调用次数加1
}

输入两棵二叉树A,B,判断B是不是A的子结构

public boolean HasSubtree(TreeNode root1,TreeNode root2) {
 boolean result = false;
    //如果两个树都不为空才会走这里
    if (root2 != null && root1 != null) {
        //如果根的值相等
        if (root1.val == root2.val) {
            //找左右子树是否相等
            result = doesTree1HaveTree2(root1, root2);
        }
        //如果上面分析的结果是不相等,继续判断A树左节点和B树或A右节点和B树
        if (!result)
            return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
    }
    return result;
}

public boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) {
    //如果右边的树为空直接说明相等
    if (node2 == null) {
        return true;
    }
    //如果左边的树为空直接返回不相等,说明不包含
    if (node1 == null) {
        return false;
    }
    //如果两个值也不相等,说明也是不相等的
    if (node1.val != node2.val) {
        return false;
    }
    //继续递归调用对应的左右子树
    return doesTree1HaveTree2(node1.left, node2.left) &&
            doesTree1HaveTree2(node1.right, node2.right);
}

求二叉树的镜像二叉树

  • 镜像二叉树是将二叉树在左右方向上旋转下,左边的节点到右边、右边的节点到左边,形如下面:
image.png
  • 思路:左右节点进行颠倒,然后递归调用下一个左、右子节点
/**
 * 转成镜像二叉树
 *
 * @param root
 */
public void Mirror(TreeNode root) {
    if (root != null) {
        TreeNode left = root.left;
        TreeNode right = root.right;
        TreeNode temp = left;
        root.left = right;
        root.right = temp;
        Mirror(left);
        Mirror(right);
    }
}

根据二叉树的前序遍历、和中序遍历顺序求出二叉树结构。

  • 树的前序遍历:先是根节点、再到左子节点、再到右子节点
  • 树的中序遍历:先是左子节点、再到根节点、再到右子节点
    剑指offer上面一道题,已知前序遍历结果是{1,2,4,7,3,5,6,8},中序遍历结果是{4,7,2,1,5,3,8,6},求该二叉树的结构。
  • 分析:前序遍历第一个节点根节点、然后去中序遍历里面找根节点左边是左子节点、根节点右边的都是右子节点部分,所以我们能确定1是根节点,4、7、2是1的左子节点部分,5、3、8、6是1的右子节点,然后在4、7、2里面继续通过前序遍历的2是首位,能确定2是左子节点,4、7是2的左子节点部分,依次类推,所以有如下结果:


    image.png
/**
 * pre前序的结果:根左右
 * in后序的结果:左根右
 * pre:{1,2,4,7,3,5,6,8}
 * in:{4,7,2,1,5,3,8,6}
 *
 * @param pre
 * @param in
 * @return
 */
public static TreeNode reConstructBinaryTree(int[] pre, int[] in) {
    TreeNode root = new TreeNode(pre[0]);
    for (int i = 0; i < pre.length; i++) {
        if (pre[0] == in[i]) {
            root.left = reConstructBinaryTree(
                    Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
            root.right = reConstructBinaryTree(
                    Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length));
        }
    }
    return root;
}

找出一个无序数组中出现超过一半次数的数字

/**
 * 计算数组里面超过一半的数字,如果没有这样的数字,则返回0
 * 先把数组排序,如果有超过一半的数字,则中间位置的数字一定是该数字
 * 然后通过出现该数的次数来判断是否超过一半
 *
 * @param array
 * @return
 */
public static int MoreThanHalfNum_Solution(int[] array) {
    Arrays.sort(array);
    int temp = array[array.length / 2];
    int num = 0;
    for (int i = 0; i < array.length; i++) {
        if (temp == array[i]) {
            num++;
        }
    }
    if (num <= array.length / 2) {
        temp = 0;
    }
    return temp;
}

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

public boolean Find(int target, int [][] array) {
    int row=0;
    int column=array[0].length-1;
    while(row=0){
        if(array[row][column]==target){
            return true;
        }
        if(array[row][column]>target){
            column--;
        }else{
            row++;
        }
    }
    return false;
}

你可能感兴趣的:(android面试笔记总结(算法篇))