算法题(三)

目录   
    1 左神部分集锦   
    2 Leetcode前150题   
    3 牛客网剑指offer   
    4 JavaG   
    5 题目中的细节处理

3 牛客网剑指offer

3.1 纯思路

3.1.1 JZ01 二维数组中的查找

(1)定义两个变量,行变量row和列变量col

(2)利用while和if条件判。若是当前数小于target,row++;若是当前数大于target,col--。

(3)若搜索到相等,直接返回true

(4)若退出while后仍然没有返回,则返回false

注意:利用while,不用两层for,可以避免了整个二维数组的遍历

3.1.2 JZ02 替换空格

思路:利用一个新的StringBuffer。遍历原StringBuffer,若不为空格,直接加入新buffer尾部,否则append("%20")

3.1.3 JZ05 用两个栈实现队列

思路:一个栈用来添加元素,一个栈用来弹出元素。重点是:在添加或弹出元素前,必须先弹出另一个栈的所有元素到当前栈。

public class Solution {

    Stack stack1 = new Stack();

    Stack stack2 = new Stack();

    public void push(int node) {

        while(!stack2.isEmpty()){

            stack1.push(stack2.pop());

        }

        stack1.push(node);

    }

    public int pop() {

        while(!stack1.isEmpty()){

            stack2.push(stack1.pop());

        }

        return stack2.pop();

    }

}

3.1.4 JZ06 旋转数组的最小数字

思路:二分法。

    我们的目的是:当进行一次比较时,一定能够确定答案在mid的某一侧。一次比较为 arr[mid]跟谁比的问题。

    一般的比较原则有:

        · 如果有目标值target,那么直接让arr[mid] 和 target 比较即可。

        · 如果没有目标值,一般可以考虑 端点

    这里我们把target 看作是右端点,来进行分析,那就要分析以下三种情况,看是否可以达到上述的目标。

· 情况1,arr[mid] > target:4 5 6 1 2 3

    arr[mid] 为 6, target为右端点 3, arr[mid] > target, 说明[first ... mid] 都是 >= target 的,因为原始数组是非递减,所以可以确定答案为 [mid+1...last]区间,所以 first = mid + 1

· 情况2,arr[mid] < target:5 6 1 2 3 4

    arr[mid] 为 1, target为右端点 4, arr[mid] < target, 说明答案肯定不在[mid+1...last],但是arr[mid] 有可能是答案,所以答案在[first, mid]区间,所以last = mid;

· 情况3,arr[mid] == target:

    如果是 1 0 1 1 1, arr[mid] = target = 1, 显然答案在左边

    如果是 1 1 1 0 1, arr[mid] = target = 1, 显然答案在右边

    所以这种情况,不能确定答案在左边还是右边,那么就让last = last - 1;慢慢缩少区间,同时也不会错过答案。

public class Solution {

    public int minNumberInRotateArray(int [] array) {

        if (array.length == 0) return 0;

        int first = 0, last = array.length - 1;

        while (first < last) { // 最后剩下一个元素,即为答案

            if (array[first] < array[last]) { // 提前退出

                return array[first];

            }

            int mid = first + ((last - first) >> 1);

            if (array[mid] > array[last]) { // 情况1

                first = mid + 1;

            }

            else if (array[mid] < array[last]) { //情况2

                last = mid;

            }

            else { // 情况3

                --last;

            }

        }

        return array[first];

    }

}

3.1.5 JZ07 斐波那契数列

思路:典型的递归。此外还可以用动态规划等。

3.1.6 JZ08 跳台阶

思路:递归。

3.1.7 JZ09 变态跳台阶

思路:从数学公式中看出的递归方法。

易知 f(n)=f(n-1)+f(n-2)+……f(1)

f(n-1)=f(n-2)+……f(1)

两式相减得f(n)=2f(n-1)

3.1.8 JZ10 矩形覆盖

思路:递归,或记忆性递归。

可以得出:f[n] = f[n-1] + f[n-2],初始条件f[1] = 1, f[2] =2

3.1.9 JZ11 二进制中1的个数

思路:利用位运算,直接找到从右向左第一个1的位置

public int NumberOf1(int n) {

        int count = 0;

        while(n != 0){

            count++;

            n = n & (n - 1);

        }

        return count;

    }

3.1.10 JZ12 数值的整数次方

3.1.11 JZ13 调整数组顺序使奇数位于偶数前面

思路:利用两个队列,第一次遍历数组时,将奇数和偶数分别放入对应队列;第二次遍历两个队列,将元素放回数组

3.1.12 JZ19 顺时针打印矩阵

思路:按层打印,每个层用左上角和右下角两个点选中。

3.1.13 JZ20 包含min函数的栈

思路:两个栈,min栈每次保存当前栈元素的最小值

3.1.14 JZ21 栈的压入、弹出序列

思路:定义一个栈,遍历数组A,对于每个元素,先压入栈,再循环弹出当前栈顶与数组B当前下标相同的元素。算法结束,若栈为空,则返回true。

3.1.15 JZ27 字符串的排列

思路:回溯

3.1.16 JZ28 数组中出现次数超过一半的数字

思路一:遍历数组,利用哈希表记录元素个数;再遍历哈希表,判断哪个元素个数超过一半

思路二:利用题目信息,直接排序数组,返回最中间元素即可。

3.1.17 JZ29 最小的K个数

思路:先排序,再取前k个数

3.1.18 JZ30 连续子数组的最大和

思路一:动态规划

思路二:利用全局变量保存最大值,最大值为负数,直接置0,遍历数组往后加

3.1.19 JZ31 整数中1出现的次数

3.1.20 JZ32 把数组排成最小的数

思路:贪心算法。

(1)将原数组转为字符串存在list中

(2)自定义Comparator对List进行排序

(3)逐位比较两个字符串,若到达字符串尾部,返回首部继续比较。

(4)利用StringBuffer将List进项拼接,并返回结果。

3.1.21 JZ33 丑数

思路:丑数能够分解成2^x3^y5^z,所以只需要把得到的丑数不断地乘以2、3、5之后并放入他们应该放置的位置即可。

(1)定义三个指针,分别代表2,3,5的个数

(2)每次取运算结果的最小值

3.1.22 JZ34 第一个只出现一次的字符

(1)定义一个包含所有字符的数组,ASCII码(一个ASCII码长度是一个字节,也就是8个bit,最高位是0作为校验位,其余7位使用0和1进行组合,所以ASCII码共有128个)

(2)遍历字符,将每个字符作为下标,将数组对应下标值加1

(3)遍历字符串,找到第一个数组值为1 的下标返回

3.1.23 JZ35 数组中的逆序对

思路:利用归并排序的过程求解

3.1.24 JZ37 数字在升序数组中出现的次数

思路:先利用二分查找找到该数的位置,再从该位置左右遍历相同的数并计数。

3.1.25 JZ40 数组中只出现一次的数字

思路:哈希表或异或运算

3.1.26 JZ41 和为S的连续正数序列

思路:穷举法,双层遍历,找到了就加入结果集。

3.1.27 JZ42 和为S的两个数字

思路:双指针法

(1)初始化双指针为一头一尾

(2)若当前两数和小于S,则左指针右移;若大于S,则右指针左移;否则,输出结果。

3.1.28 JZ43 左旋转字符串

思路一:利用标准库,s.substring()先进行字符串拆分,再进行拼接。

思路二:先转为字符数组,再借助辅助数组进行移位。

3.1.29 JZ44 翻转单词顺序列

思路:先利用str.split(" ")将字符串按照空格分割为字符串数组,再利用数组移位或者是栈进行翻转。

3.1.30 JZ45 扑克牌顺子

思路:

(1)先排序数组

(2)遍历数组,记录数组中0的个数和不同非0数字之间的差值

(3)根据0的个数和差值进行判断

3.1.31 JZ46 孩子们的游戏(圆圈中最后剩下的数)

思路:递归,当我们知道了 f(n - 1, m) 对应的答案 x 之后,我们也就可以知道,长度为 n 的序列最后一个删除的元素,应当是从 m % n 开始数的第 x 个元素。

public int LastRemaining_Solution(int n, int m) {

        if (n <= 0 || m <= 0) return -1;

        return n == 1 ? 0 : (LastRemaining_Solution(n - 1, m) + m) % n;
}

3.1.32 JZ47 求1+2+3+...+n

思路:递归

3.1.33 JZ48 不用加减乘除做加法

3.1.34 JZ49 把字符串转换成整数

思路:注意越界问题即可。用布尔值记录正负号,再逐位计算。

3.1.35 JZ50 数组中重复的数字

思路:利用set进行遍历即可

3.2 链表

3.2.1 JZ03 从尾到头打印链表

思路一:利用一个栈,将元素顺序倒置。

思路二:正序遍历并保存元素至链表,利用Collections.reverse(list)反转链表。

3.2.2 JZ14 链表中倒数第k个结点

思路:快慢指针,首先让快指针先行k步,然后让快慢指针每次同行一步,直到快指针指向空节点,慢指针就是倒数第K个节点。

3.2.3 JZ15 反转链表

3.2.4 JZ16 合并两个排序的链表

思路:归并排序

3.2.5 JZ25 复杂链表的复制

思路:利用Map集合存储<链表节点,新建节点>,再遍历链表,建立新建链表之间的关系。

3.2.6 JZ36 两个链表的第一个公共结点

思路:这道题默认无环

(1)都无环:得到两个链表的长度,长链先走,再和短链一起走

(2)都有环:

        · 若入环点相同,同无环解法

        · 若入环点不同,从一个入环点往下遍历,在碰到自己之前碰到了另一个入环点,则返回该入环点;否则无相交点

其他情况都无相交点。

3.3 二叉树

3.3.1 JZ04 重建二叉树

思路:递归。利用中序和前序中,根节点的位置进行划分左右子树。

3.3.2 JZ17 树的子结构

思路:递归,选中结点递归是否是子树,若不是子树,再递归选中结点的左右节点查找子树。

3.3.3 JZ18 二叉树的镜像

思路:递归,DFS,先交换左右节点,再继续递归左右子节点

3.3.4 JZ22 从上往下打印二叉树

思路:利用队列,层序遍历,BFS。

3.3.5 JZ23 二叉搜索树的后序遍历序列

思路:递归,根据元素大小进行左右递归分区,知道分区只剩一个元素或0个元素,往前返回。

3.3.6 JZ24 二叉树中和为某一值的路径

思路:回溯,每个元素先加入,若满足条件,加入结果集,再遍历左右子树,然后回溯。

3.3.7 JZ26 二叉搜索树与双向链表

思路:先中序遍历结果存储在链表中,再遍历链表,连接左右指针。

3.3.8 JZ38 二叉树的深度

思路:递归,递归过程中将左右子树的最大值加1;

3.3.9 JZ39 平衡二叉树

思路:递归,递归中判断左右字数高度差

4 JavaG

5 题目中的细节处理

5.1 在遍历中,对特殊值(特别是i = 0时的处理)

for(int i = 0; i < m; i++){

dp[i][0] = grid[i][0] + ( (i - 1 < 0)? 0: dp[i - 1][0]);

}

5.2 取字符串的子串

    String s = "123";

    s.substring(0,2); -->"12";

注意substring中没有单词大写!

5.3 取数组的子数组

Arrays.copyOfRange(arr,start,end);--> [start,end)

5.4 翻转链表

Collections.reverse(list);

5.5 Integer类型的最大值和最小值属性

int maxSum = Integer.MAX_VALUE;

int minSum = Integer.MIN_VALUE; 

5.6 StringBuffer相关操作

(1)添加基础类型变量

    strbuff.append(...)

(2)删除对应下标的字符

    strbuff.deleteCharAt(index)

    strbuff.delete(from, to)

(3)与String相同的API

    strbuff.charAt(index)
    strbuff.length()
    strbuff.substring(from, to)

(4)转换为String

    strbuff.toString()

5.7 初始化基本类型数组

boolean[] used

Arrays.fill(used, false);

5.8 链表转为String

String.join(".", list)

5.9 字符串转整数

int a = Integer.valueOf(s.substring(i - 2, i))

5.10 字符串转字符数组

String s = "abc";

char[] arr = s.toCharArray();

5.11 Character相关API

Character.isLetterOrDigit('c');
Character.isDigit('1');
Character.isLetter('c');
Character.toLowerCase('C');
Character.toUpperCase('c');

5.12 字符串的trim方法

trim() 方法用于删除字符串的头尾空白符。public class Test {

    public static void main(String args[]) {

        String Str = new String("    https://blog.csdn.net/Mrs_chens    ");

        System.out.print("原始值 :" );

        System.out.println( Str );

        System.out.print("删除头尾空白 :" );

        System.out.println( Str.trim() );

    }

}

5.13 Arrays工具类中自带二分查找

int index = Arrays.binarySearch(array, target);

5.14 CompareTo方法

java中的compareto方法的详细介绍_像风一样奔跑-CSDN博客

    是String类中的方法

你可能感兴趣的:(算法题(三))