算法之题2(其他)

Android面试总结(算法篇)

链表常见题

  • 常见题型有链表翻转、求倒数第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);
}

求二叉树的镜像二叉树

  • 镜像二叉树是将二叉树在左右方向上旋转下,左边的节点到右边、右边的节点到左边,形如下面:
 
  • 思路:左右节点进行颠倒,然后递归调用下一个左、右子节点
/**
 * 转成镜像二叉树
 *
 * @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的左子节点部分,依次类推,所以有如下结果:

/**
 * 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<array.length&&column>=0){
        if(array[row][column]==target){
            return true;
        }
        if(array[row][column]>target){
            column--;
        }else{
            row++;
        }
    }
    return false;
}
作者:的一幕
链接:https://www.jianshu.com/p/820bc47859fb

84.反转链表
public class ReverseLinkedList {
/**
* 206. Reverse Linked List
time : O(n);
space : O(1);
* @param head
* @return
* 思路是在原链表之前建立一个空的newHead(pre),因为首节点会变,然后从head开始,将之后的一个节点移到 * newHead(pre)之后,重复此操作直到head成为末节点为止
*/
public static ListNode reverseList(ListNode head) {
//if(head==null) return head;这样写也行,下面一行注释掉也行
if (head == null || head.next == null) return head;
ListNode pre = null;
while (head != null) {
//临时节点暂存当前节点的下一个节点
ListNode temp = head.next;
//当前节点指向他前面的节点
head.next = pre;
//然后变换节点
pre = head;
head = temp;
}
return pre;}
//递归
class Solution {
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode last=reverseList(head.next);//最后last是5 head是1 last指向前一个last
head.next.next=head;
head.next=null;
return last;
}}
83.字符串转整数
public class StringtoInteger {
/**
* time : O(n)
* space : O(1)
* @param str
* @return
*/
public int myAtoi(String str) {
if (str == null || str.length() == 0) return 0;
//去掉前尾的空白符
str = str.trim();
if(str.length()==0) return 0;
char firstChar = str.charAt(0);
int sign = 1;//注意是1不是0 不然若没有‘+’‘-’,那么就res*sign=0
int start = 0;
long res = 0;
if (firstChar == '+') {
//判断+ —性
sign = 1;
//从下一位符号开始判断
start++;
} else if (firstChar == '-') {
sign = -1;
start++;
}
for (int i = start; i < str.length(); i++) {
//Character.isDigit()判断是不是一个数字
if (!Character.isDigit(str.charAt(i))) {
//不是数字
return (int) res * sign;
}
//-143
//0*10+1=1
//1*10+4=14
//14*10+3=143
//charAt(i)是字符串中的第i个字符,s.charAt(i)就是S中的第i个字符,因为字符都是用ASCII码存储的,存储
//的事ASCII码值,用s.charAt(i)减去字符‘0’,就是用s.charAt(i)的码值减去‘0’的码值,得到的值干好就是s
//中第i个字符的十进制值。
res = res * 10 + str.charAt(i) - '0';
//越界
if (sign == 1 && res > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (sign == -1 && res > Integer.MAX_VALUE) return Integer.MIN_VALUE;
}
return (int) (res*sign);//注意要加括号,不加括号的话,res要放在前面
}}
82.整数翻转
public class ReverseInteger {
/**
* 7. Reverse Integer
* Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
int :
-2147483648 ~ 2147483647
corner case : 越界
time : O(n);
space : O(1);
* @param x
* @return
*/
// 1.取模运算多见于计算机领域,取余运算一般用于数学领域。
// 2.取模运算(取余运算)计算步骤
// a、求整数商
// c=a/b
// b、求模(余数)
// r=a-c*b
//两者不同点:取模运算 c 向负无穷远处取整,取余运算 c 向 0 方向取整。
//结论:a 为正整数时,取模运算和取余运算结果相同;a 为负整数时,两者结果不同。
public static int reverse(int x) {
long res = 0;
while (x != 0) {
res = res * 10 + x % 10;
x /= 10;
if (res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) return 0;
}
return (int)res;}}
8.两个链表相加
public class AddTwoNumbers {
/**
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
time : O(n)
space : O(n)
* @param l1
* @param l2
* @return
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummyNode = new ListNode(0);
ListNode cur = dummyNode;
int sum = 0;
while (l1 != null || l2 != null) {
if(l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if(l2 != null) {
sum += l2.val;
l2 = l2.next;
}
cur.next = new ListNode(sum % 10);//真正存入的结果值
sum /= 10;//结果0、1,相当于进位,结果用于下次的链表值相加
cur = cur.next;
}
//用于判断最后一次的结果,是否要进位+1
if(sum == 1) {
cur.next = new ListNode(1);
}
return dummyNode.next;//因为dummyNode是不动的,一直==0,cur是往后遍历的,结果是从cur.next开始放的
}}
76.二叉树前序,中序,后序 ,层序,锯齿遍历
1.前序迭代
public class BinaryTreePreorderTraversal {
//根左右
//方法一:递归
public static List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
helper(res, root);
return res;
}
public static void helper(List<Integer> res, TreeNode root) {
if (root == null) return;
res.add(root.val);
helper(res, root.left);
helper(res, root.right);
}
//方法二:迭代
public static List<Integer> preorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
//记得先让右子树入栈,栈是先进后出的
if (cur.right != null) stack.push(cur.right);
if (cur.left != null) stack.push(cur.left);
res.add(cur.val);
}
return res;
}
}
2.中序
package leetcode;
public class BinaryTreeInorderTraversal {
/**
* 94. Binary Tree Inorder Traversal
* Given a binary tree, return the inorder traversal of its nodes' values.
* time : O(n)
* space : O(n)
* @param root
* @return
*/
//方法一:递归
//左中右
public static List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
helper(res, root);
return res;
}

public static void helper(List<Integer> res, TreeNode root) {
if (root == null) return;
helper(res, root.left);
res.add(root.val);
helper(res, root.right);
}
//方法二:迭代
public static List<Integer> inorderTraversal2(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;//注意中序遍历进入循环前是没有入栈操作的,它需要不断的顺着根节点找下面的节点,所以首先根节点不能为空
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;//找到最左节点
}
cur = stack.pop();//1
res.add(cur.val);//左根右:自身->右子节点
cur = cur.right;//当某个节点的右子节点为null后,那么需要从栈中弹出新的节点继续遍历(1处),所以||stack!=null,当cur==null且栈空,说明中序遍历结束
}
return res;
}
}
3.后序
package leetcode;
public class BinaryTreePostorderTraversal {
/**
* 145. Binary Tree Postorder Traversal
* time : O(n);
* space : O(n);
* @param root
* @return
*/
//方法一:递归
//左右根
public static List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
helper(res, root);
return res;
}
public static void helper(List<Integer> res, TreeNode root) {
if (root == null) return;
helper(res, root.left);
helper(res, root.right);
res.add(root.val);
}
//方法二:迭代
public static List<Integer> postorderTraversal2(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode cur = stack.pop();
res.addFirst(cur.val);//加在前面addFirst是LinkedList的方法(在列表首部添加元素),ArrayList的方法是add(0,cur.val);
if (cur.left != null) stack.push(cur.left);//左
if (cur.right != null) stack.push(cur.right);//右
//res.addFirst(cur.val);放在这里也一样,其实它就是模拟了栈的功能//根
}
return res;
}
//双栈法,如果要求直接输出,不是返回List<Integer> ,可以用上
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root==null) return res;
Stack<TreeNode> stack = new Stack();
Stack<TreeNode> stack2 = new Stack();
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
if(cur.left!=null) stack.push(cur.left);
if(cur.right!=null) stack.push(cur.right);
stack2.push(cur);
}
while(!stack2.isEmpty()){
res.add(stack2.pop().val);
}
return res;
}
}
4.层序
package leetcode;
import org.omg.PortableServer.LIFESPAN_POLICY_ID;
public class BinaryTreeLevelOrderTraversal {

/**
* 102. Binary Tree Level Order Traversal
3
/ \
9 20
/ \
15 7
[
[3],
[9,20],
[15,7]
]
time : O(n);
space : O(n);
* @param root
* @return
*/
//https://www.bilibili.com/video/BV1xa411A76q?p=18手画图解版+代码p18
public static List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode cur = queue.poll();
if (cur.left != null) queue.offer(cur.left);
if (cur.right != null) queue.offer(cur.right);
list.add(cur.val);
}
res.add(list);
}
return res;
}
//********递归版*********
public static List<List<Integer>> levelOrder2(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
helper(res, root, 0);
return res;
}

public static void helper(List<List<Integer>> res, TreeNode root, int level) {
if (root == null) return;
if (level >= res.size()) {
res.add(new ArrayList<>());
}
res.get(level).add(root.val);
helper(res, root.left, level + 1);
helper(res, root.right, level + 1);}
74.锯齿遍历
public class BinaryTreeZigzagLevelOrderTraversal {
/**
* 103. Binary Tree Zigzag Level Order Traversal
3
/ \
9 20
/ \
15 7
[
[3],
[20,9],
[15,7]
]
time : O(n)
space : O(n);
* @param root
* @return
*/
public static List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean x = true;//奇数层还是偶数层
while (!queue.isEmpty()) {
int size = queue.size();
//把他当成栈/数组使用,比我的方法更好,他少使用了一个栈
//每次都new一个,就不需要clear了
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode cur = queue.poll();
if (x) {
list.add(cur.val);
} else {
list.add(0, cur.val);
}
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
res.add(list);
x = x ? false : true;//取反
}
return res;}
73.Pow(x, n)
public class Pow {
public double myPow1(double x, int n) {//递归版
if (n > 0) {
return pow(x, n);
} else {
return 1.0 / pow(x, n);
}
}
public double pow (double x, int n) {
if (n == 0) {
return 1;
}
double y = pow(x, n / 2);
if (n % 2 == 0) {
return y * y;
} else {
return y * y * x;
}
}
//time:O(logn),space:O(1)
public static double myPow2(double x, int n) {
if (n == 0) return 1;
double res = 1;
// int : -6.. ~ +6.. -2^32 ~ 2 ^32-1 Integer.MIN_VALUE
long abs = Math.abs((long)n);
while (abs > 0) {
if (abs % 2 != 0) {
res *= x;//有几次为奇数,就执行几次 7/2一次 3/2 一次 1/2一次
}
x *= x;//记录上一轮的结果
abs /= 2;
}
if (n < 0) {
return 1.0 / res;
}
return res;}
72.二叉树的最小深度(LC111)
public class MinimumDepthofBinaryTree {
/**
* 111. Minimum Depth of Binary Tree
* Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
time : O(n);
space : O(H);H树的高度
* @param root
* @return
*/
//还是用深度优先搜索 DFS 来完成,万能的递归啊。首先判空,若当前结点不存在,直接返回0。然后看若左子结点不存在,那么对右子结点调用递归函数,并加1返回。反之,若右子结点不存在,那么对左子结点调用递归函数,并加1返回。若左右子结点都存在,则分别对左右子结点调用递归函数,将二者中的较小值加1返回即可
public static int minDepth(TreeNode root) {
//这道题递归条件里分为2种情况
if (root == null) return 0;
//1.如果左孩子和由孩子其中一个为空,那么需要返回比较大的那个孩子的深度
if (root.left == null || root.right == null) {
//必有一个为null,相当于为0,另一个返回深度+1
return Math.max(minDepth(root.left), minDepth(root.right)) + 1;
}
//2.一种情况,也就是左右孩子都不为空,返回最小深度+1即可
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
} }
71.平衡二叉树
public class BalancedBinaryTree {
算法流程:
helper(root):
递归返回值:
当节点root 左 / 右子树的高度差 <2 :则返回以节点root为根节点的子树的最大高度,即节点 root 的左右子树中最大高度加 1 ( max(left, right) + 1 );
当节点root 左 / 右子树的高度差 ≥2:则返回 −1 ,代表 此子树不是平衡树 。
递归终止条件:
当越过叶子节点时,返回高度 0 ;
当左(右)子树高度 left== -1 时,代表此子树的 左(右)子树 不是平衡树,因此直接返回 −1;
isBalanced(root) :
返回值: 若 recur(root) != 1 ,则说明此树平衡,返回 true ;否则返回 false。
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return helper(root) != -1;
}
public int helper(TreeNode root) {
if (root == null) return 0;
int l = helper(root.left);
int r = helper(root.right);
if (l == -1 || r == -1 || Math.abs(l - r) > 1) {
return -1;
}
return Math.max(l, r) + 1;}}
62.回文数(LC9)
public class PalindromeNumber {
/**
* 9. Palindrome Number
time : O(n) space : O(1)
*/
public boolean isPalindrome(int x) {
if (x < 0 || x != 0 && x % 10 == 0) return false;//x%10==0能被10整除的都不是
int palind = x;
int rev = 0;
while (x > 0) {
rev = rev * 10 + x % 10;
x /= 10;
}
return palind == rev;}}
61.两数相加(LC2)
6.计数质数(LC204)
package leetcode;
public class CountPrimes {
/**
* 厄拉多塞筛法,求一组质数,时间复杂度仅有O(nloglogn)https://www.cnblogs.com/jiaxin359/p/6081629.html
* 如果从1到n-1分别判断质数,时间复杂度为O(nsqrt(n)))
*/
public int countPrimes(int n) {
boolean[] notPrime = new boolean[n];
int res = 0;
for (int i = 2; i < n; i++) {//如果是2,没有进入循环
if (notPrime[i] == false) {//就是质数
res++;
for (int j = 2; i * j < n; j++) {
notPrime[i * j] = true;//i的j倍数都是非质数,将i*j排除掉
}
}
}
return res;}}
53.删除链表的倒数第 N 个结点(LC19)
package leetcode;
public class RemoveNthNodeFromEndofList {
//https://www.bilibili.com/video/BV1Pq4y1j78o?p=10 b站讲解
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
ListNode dummy = new ListNode(0);
ListNode slow = dummy;
ListNode fast = dummy;
dummy.next = head;
for (int i = 0; i <= n; i++) { //注意是<=n
fast = fast.next;
}
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;//把中间要移除的断掉
return dummy.next;
}}
52.环形链表(LC141 判断链表是否有环)
package leetcode;
public class LinkedListCycle {
//time : O(n); space : O(1);
//这道题是快慢指针的经典应用。只需要设两个指针,一个每次走一步的慢指针和一个每次走两步的快指针,如果链表里有环的话,两个指针最终肯定会相遇
public static boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;//遇到
}
}
return false;} }
51.环形链表 II(LC142 找到环形链表的入口结点)
<img src="https://images0.cnblogs.com/blog/354747/201311/05171805-64db9f059a1641e7afaf3dd8223c4fe7.jpg" alt="img" style="zoom: 67%;" />
public class LinkedListCycleII {
/**
* Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
* time : O(n)
* space : O(1)
*/
//题解:https://www.cnblogs.com/hiddenfox/p/3408931.html
//因为fast的速度是slow的两倍,所以fast走的距离是slow的两倍,有 2(a+b) = a+b+c+b,可以得到a=c(这个结论很重要!)。
//我们已经得到了结论a=c,那么让两个指针分别从X和Z开始走,每次走一步,那么正好会在Y相遇!也就是环的第一个节点。
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) return null;
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (fast == slow) {//fast比slow多走一个环的距离
ListNode slow2 = head;
while (slow != slow2) {//不管fast绕了多少圈和slow相遇,依然满足这个情况
slow = slow.next;
slow2 = slow2.next;
}
return slow;
}
}
return null;
}
}

4.斐波拉切数列
/*大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39*/
//第1题:Fibonacci数列
//判题OJ:https://www.nowcoder.com/practice/c6c7742f5ba7442aada113136ddea0c3?tpId=13&tqId=11160&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
//正推法
public int Fibonacci(int n) {
//first:前面2个,second:前面1个
int first = 1, second = 1;
int third = 0;
if(n == 1 || n == 2) return 1;
for(int i = 3; i <= n; i++){
third = first + second;//将上一次保留下来的相加 例如5=4+3
first = second;//保留上一轮的结果3
second = third;//保留这一轮的结果4
}
return third;
}
3.青蛙跳台阶
//第1题:跳台阶
//判题OJ:https://www.nowcoder.com/practice/22243d016f6b47f2a6928b4313c85387?tpId=13&tqId=11162&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
public int climbStairs(int n) {
if (n <= 2) return n;
int fisrt = 1;
int second = 2;
int third = 3;
for (int i = 2; i < n; i++) {
third = fisrt + second;
fisrt = second;
second = third;
}
return third;
}

//第2题:变态跳台阶
//判题OJ:https://www.nowcoder.com/practice/22243d016f6b47f2a6928b4313c85387?tpId=13&tqId=11162&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
每个台阶可以看作一块木板,让青蛙跳上去,n个台阶就有n块木板,最后一块木板是青蛙到达的位子,必须存在,其他n-1块木板可以任意选择是否存在,则每个木板有存在和不存在两种选择,n-1块木板就有2^(n-1)种,可以直接得到结果,不用那么麻烦分析吧
public int JumpFloorII(int target) {
return 1<< target-1;
}
//类似题: https://www.zybang.com/question/104cecdfb73ed0ca724706dccad2f9d0.html
//跳台阶3:(此题好像不能用非递归)
//n阶楼梯,每次能走1阶或2阶或5阶,问:到n阶总共有多少种走法
public int jump(int n) {
if (n == 0) return 1;
if (n <= 2) return n;
if (n < 5) return jump(n - 1) + jump(n - 2);
return jump(n - 1) + jump(n - 2) + jump(n - 5);
}
2.1个数组(有重复元素)找相加等于0的数有多少对
//有点力扣167的意思
//给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。见题解下的双指针解法
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0;
int j = numbers.length - 1;
while (i < j) {
int sum = numbers[i] + numbers[j];
if (sum < target) {
i++;
} else if (sum > target) {
j--;
} else {
return new int[]{i+1, j+1};
}
}
return new int[]{-1, -1};
}}
//以上不是本题的题解 //思路:先排序,然后双指针解法,跟上面一样
1.计算View树的深度
private int maxDeep(View view) {
//当前的view已经是最底层view了,不能往下累加层数了,返回0,代表view下面只有0层了
if (!(view instanceof ViewGroup)) {
return 0;
}
ViewGroup vp = (ViewGroup) view;
//虽然是viewgroup,但是如果并没有任何子view,那么也已经是最底层view了,不能往下累加层数了,返回0,代表view下面只有0层了
if (vp.getChildCount() == 0) {
return 0;
}
//用来记录最大层数
int max = 0;
//广度遍历view
for (int i = 0; i < vp.getChildCount(); i++) {
//由于vp拥有子view,所以下面还有一层,因为可以+1,来叠加一层,然后再递归几岁算它的子view的层数
int deep = maxDeep(vp.getChildAt(i)) + 1;
//比较哪个大就记录哪个
if (deep > max) {
max = deep;
}
}
return max;}

posted on 2020-03-26 22:57  左手指月  阅读(265)  评论(0编辑  收藏  举报