LeetCode双指针

面试10.01 合并排序的数组

题目

分析

1.最简单的方法:a数组从m之后开始讲b的放进去之后排序即可。
2.双指针可以确定插入位置然后进行挪,这种方法复杂度会低很多。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class HeBingArr {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m=input.nextInt();
int n=input.nextInt();
int[] a=new int[n+m];
int[] b=new int[n];
for(int i=0;i<m;i++) {
a[i] = input.nextInt();
}
for(int i=0;i<n;i++) {
b[i] = input.nextInt();
}
merge(a,m,b,n);
System.out.println(Arrays.toString(a));
}

public static void merge(int[] a, int m, int[] b, int n) {
int j=0;
for(int i=m;i<m+n;i++){
a[i]=b[j++];
}
Arrays.sort(a);
}

}

结果


面试10.09 排序矩阵查找(双指针控制行和列)

题目

分析

1. 设置h和l双指针,从第0行和第m-1列开始,控制范围满足:h<matrix.length&&l>=0
2. 通过while循环然后有三种情况:
    2.1 如果当前值比target小: 说明这行前面的都比target小 就换下一行 h++
    2.2 如果当前值比target大: 说明这列下面的都比target大 就换前一行 l--
    2.3 如果相等就直接返回true  所以外面方法默认返回就写成false

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ShengXu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m=input.nextInt();
int n=input.nextInt();
int[][] a=new int[m][n];
for(int i=0;i<m;i++) {
for(int j=0;j<n;j++) {
a[i][j] = input.nextInt();
}
}
int target=input.nextInt();
System.out.println(searchMatrix(a,target));
}

public static boolean searchMatrix(int[][] matrix, int target) {
if(matrix.length==0){ //一定要有判断数组是否存在 不然后面的l这个指针就会异常
return false;
}
int h=0; //行指针
int l=matrix[0].length-1; //列指针
while(h<matrix.length&&l>=0){
if(matrix[h][l]==target){
return true;
}
if(matrix[h][l]<target){
h++; //这行前面的都比这个小 换下一行
}else{
l--; //这列下面的都比这个大 所以换前一列
}
}
return false;
}

}

结果


面试16.06 最小差(ab排序后指针控制移)

题目

分析

1. 主要是先将a和b排序之后我们就可以双指针进行移动
2. 思路:
    int diff = a[i] - b[j]
    如果 diff < 0 ,表示 a[i] 小于 b[j] ,a 尽可能接近 b,那么 i++
    如果 diff > 0 ,表示 a[i] 大于 b[j] ,b 尽可能接近 a,那么 j++

    特殊情况:
    a = {1,2,3,4,5}
    b = {6,7,8,9,10}
    如果 a 数组最大值比 b 数组最小值还小,那么 a 数组 i 会一直右移,直到到达边界 break
    */

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class ZuiXiaoCha {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m=input.nextInt();
int n=input.nextInt();
int[] a=new int[m];
int[] b=new int[n];
for(int i=0;i<m;i++) {
a[i] = input.nextInt();
}
for(int i=0;i<n;i++) {
b[i] = input.nextInt();
}
System.out.println(smallestDifference(a,b));
}

public static int smallestDifference(int[] a, int[] b) {
int alen = a.length;
int blen = b.length;
//a和b排序之后方便查找相近的值在哪
Arrays.sort(a);
Arrays.sort(b);
//给最小值最好赋给其他特定值 如果是数组的内容有可能会报错
int minVal = Integer.MAX_VALUE;
int i=0;
int j=0;
while(i<alen&&j<blen){ //i和j分别是控制a和b数组的变化
// 使用 long,防止 -2147483648 转正数后还是 -2147483648
long cha=a[i]-b[j]; //计算出当前两个数组值的差
minVal = (int)Math.min(Math.abs(cha), minVal); //minVal放的就是最后的结果
if(cha<0){
i++; //a数组的比b数组的小 a数组的值要尽可能靠近b
}else{
j++; //相反b的小 就要往a靠近
}
}
return minVal;
}

}

结果


面试17.11 单词距离(list集合存放出现位置然后比较)

题目

分析

使用两个list集合分别存放单词出现位置,然后循环遍历得到最小值

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class DanCiLen {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m=input.nextInt();
String[] a=new String[m];
for(int i=0;i<m;i++) {
a[i] = input.next();
}
String word1=input.next();
String word2=input.next();
System.out.println(findClosest(a,word1,word2));
}

public static int findClosest(String[] words, String word1, String word2) {
int min=Integer.MAX_VALUE;
List<Integer> list1=new ArrayList<>();
List<Integer> list2=new ArrayList<>();
for(int i=0;i<words.length;i++)
{
if(word1.equals(words[i]))
{
list1.add(i); //list1存放单词word1出现的位置
}
if(word2.equals(words[i])) {
list2.add(i); //list2存放单词word2出现的位置
}
}
for(int j=0;j<list1.size();j++)
{
for(int k=0;k<list2.size();k++)
{
int cha=list1.get(j)-list2.get(k); //看
min=Math.min(min,Math.abs(cha));
}
}
return min;
}

}

结果


面试17.21 接雨水(低动高不动/木桶效应由最短的决定)

题目

分析

1. 核心思路:缓存两端最大值,从最大值较小的一边进行储水结算、移动,并更新最大值。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class JieYuShui {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m=input.nextInt();
int[] a=new int[m];
for(int i=0;i<m;i++) {
a[i] = input.nextInt();
}
System.out.println(trap(a));
}

public static int trap(int[] height) {
int l=0; //左指针
int r=height.length-1; //右指针
int lmax=height[l]; //左边最大值
int rmax=height[r]; //右边最大值
int res=0;
while(l<r){
if(lmax<rmax){ //左边低 算左边的高度
res+=lmax-height[l];
l++;
lmax=Math.max(height[l],lmax); //更新左边最大值
}else{ //右边低 算右边的高度
res+=rmax-height[r];
r--;
rmax=Math.max(height[r],rmax); //更新右边最大值
}
}
return res;
}

}

结果


面试48. 最长不含重复字符的子字符串(双指针/动态规划)

题目

分析

https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/solution/mian-shi-ti-48-zui-chang-bu-han-zhong-fu-zi-fu-d-9/

1. 哈希表统计:遍历字符串s时,使用哈希表记为dic统计各字符最后一次索引位置。
2. 左边界i获取:遍历s[j]时,可通过访问哈希表dic[s[j]]获取最近的相同字符的索引i 。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ZuiChangZiString {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.next();
System.out.println(lengthOfLongestSubstring(s));
}

public static int lengthOfLongestSubstring(String s) {
Map<Character, Integer> map = new HashMap<>();
int res = 0, tmp = 0;
for(int j = 0; j < s.length(); j++) {
// getOrDefault代表当哈希表包含键key时返回对应value,不包含时返回默认值default。
int left = map.getOrDefault(s.charAt(j),-1);

map.put(s.charAt(j), j); // 更新哈希表(将对应的字母和下标放入)

if(tmp<(j-left)){
tmp++;
}else{
tmp=j-left;
}
res = Math.max(res, tmp); // res一直是每一次变化之后的最大值
}
return res;
}

}

结果


LeetCode动态规划

面试08.01 三步问题(跳台阶进阶版动态规划)

题目

分析

1. 原来只能一次性跳1/2节台阶,最后就是三个数字不断循环
2. 现在就相当于是四个数字变化,但是可能后面的数字比较大,因此每次计算时候b+c先进行取余之后再个d进行取余即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SanBu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(waysToStep(n));
}

public static int waysToStep(int n) {
int a=1; //一个台阶一种走法 1
int b=2; //二个台阶两种走法 1+1 / 2
int c=4; //三个台阶四种走法 1+1+1 / 1+2 / 2+1 / 3
int d=0;
for(int i=1;i<n;i++){
d=(a+(b+c)%1000000007)%1000000007;
a=b;
b=c;
c=d;
}
return a;
}

}

结果


面试08.02 迷路的机器人

题目

分析

代码

1
2


结果


面试08.11 硬币

题目

分析

代码

1
2


结果


面试17.16 按摩师/打家劫舍(a[0]+a[2]和a[1]对比)

题目

分析

1. 思路:(当前+前两个) ?(前一个)
2. 第一种o(n):dp[i]=Math.max(dp[i-1],nums[i]+dp[i-2]);
3. 第二种o(1): a b c三个变量递进循环

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class AnMoShi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(massage(a));
}

//O(n)
public static int massage(int[] nums) {
int n = nums.length; //数组长度
if (n == 0) {
return 0; //如果数组长度为0就返回0
}
if (n == 1) {
return nums[0]; //如果只有一个就返回这个值
}
int[] dp = new int[n]; //存放结果
dp[0] = nums[0]; //第一个值就是当前的第一个
dp[1]=Math.max(nums[0], nums[1]); //判断是1开始还是2开始
for(int i=2;i<n;i++){
dp[i]=Math.max(dp[i-1],nums[i]+dp[i-2]);
}

return dp[n-1]; //返回最后一个值
}

//O(1)
public int massage(int[] nums) {
int a = 0, b = 0;
for (int i = 0; i < nums.length; i++) {
int c = Math.max(b, a + nums[i]);
a = b;
b = c;
}
return b;
}

}

结果


面试17.23 最大黑方阵(纯劳力题不推荐)

题目

分析

参考LeetCode别人的代码思路,

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
int[][] matrix;
int[] result=new int[]{0,0,0};
public int[] findSquare(int[][] matrix) {
this.matrix=matrix;
if(matrix.length==0){
return new int[]{};
}
for(int i=0;i<matrix.length-result[2];i++){
for(int j=0;j<matrix.length-result[2];j++){
if(matrix[i][j]==0){
int count=1;
while(count+i<matrix.length&&count+j<matrix.length
&&matrix[count+i][j]==0&&matrix[i][count+j]==0
){
count++;
}
int actualLen=isBlackMatrix(i,j,count);
if(actualLen>result[2]){
result[0]=i;
result[1]=j;
result[2]=actualLen;
}
}
}
}
if(result[2]==0){
return new int[]{};
}
return result;
}
public int isBlackMatrix(int i,int j,int size){//recursive check
if(size==1){
return size;
}
else{
for(int x=0;x<size;x++){
if(matrix[i+size-1][j+x]==0&&matrix[i+x][j+size-1]==0){
continue;
}
else{
int miniLen=isBlackMatrix(i,j,size-1);
return miniLen;
}
}
return size;
}
}
}

结果


面试12 矩阵中的路径/单词搜索

题目

分析

代码

1
2


结果


面试42 连续子数组的最大和/最大子序列和(抓住sum大小)

题目

分析

参考大佬思路:https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/solution/mian-shi-ti-42-lian-xu-zi-shu-zu-de-zui-da-he-do-2/

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class LianXuZiarr {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int r=input.nextInt();
int[] a=new int[r];
for(int i=0;i<r;i++) {
a[i] = input.nextInt();
}
System.out.println(maxSubArray(a));
}

public static int maxSubArray(int[] nums) {
int ans=nums[0]; //当前最大就是第一个数
int sum=0;
for(int i=0;i<nums.length;i++){
if(sum>0){
sum+=nums[i]; //sum>0就直接加进去现在的值
}else{
sum=nums[i]; //反之让当前值替换掉
}
ans=Math.max(ans,sum); //ans相当于替换为一轮的最大值
}
return ans;
}

}

结果


面试63 购票最大利润(双指针/动态规划)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class GuPiao {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int r=input.nextInt();
int[] a=new int[r];
for(int i=0;i<r;i++) {
a[i] = input.nextInt();
}
System.out.println(maxProfit(a));
}

public static int maxProfit(int[] prices) {
if(prices.length == 0) {
return 0;
}
int min=prices[0];
int[] dp=new int[prices.length];
for(int i=1;i<prices.length;i++){
min=Math.min(prices[i-1],min); //当前i所在值前面一个的最小值
dp[i]=Math.max(dp[i-1],prices[i]-min); //前面的最优解和最小的收益差的比较
}
return dp[prices.length-1];
}

}

结果


数组中的最长山脉(分两个动规解决)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[] nums=new int[]{2,1,4,7,3,2,5}; //可以设定数组 或者初始化
System.out.println(longestMountain(nums)); //调用方法返回结果
}

public static int longestMountain(int[] a) {
int res=0; //接住结果
int len=a.length; //获取数组长度
int flag=3; //山脉的标准长度
int[] left=new int[len]; //记录所有节点左边的最大扩展
left[0]=0; //第一位赋值0
int[] right=new int[len]; //记录所有节点右边的最大扩展
right[a.length-1]=0; //最后一位赋值0
//计算所有节点左边能扩展多少
for(int i=1;i<a.length;i++){
if(a[i]>a[i-1]){ // 2 8 这样的话说明可以扩展
left[i]=left[i-1]+1; //前面的基础上+1
}else{
left[i]=0;
}
}
//计算所有节点右边能扩展多少
for(int i=a.length-2;i>=0;i--){
if(a[i]>a[i+1]){ // 8 2 这样的话说明可以扩展
right[i]=right[i+1]+1; //前面的基础上+1
}else{
right[i]=0;
}
}
//最终找到最长的结果
for(int i=0;i<len;i++){
if(left[i]>0&&right[i]>0){ //一定要都有左右山脉
res=Math.max(res,(left[i]+right[i]+1)); //求左右之和最大的
}
}
return res;
}

}

结果


LeetCode数学问题

面试02.05 链表求和(string和int转换加)

题目

分析

1. 先使用stringbuilder对象将两个链表按序加(其实是反的)
2. 通过自己写的函数翻过去就是原来的数字(调正)
3. 相加之后拆开(一个数字拆成链表形式)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class LianBiaoHe {
public static void main(String[] args) {
ListNode l11=new ListNode(7); //添加7->1->6
ListNode l12=new ListNode(1);
ListNode l13=new ListNode(6);
l11.next=l12;
l12.next=l13;

ListNode l21=new ListNode(5); //添加5->9->2
ListNode l22=new ListNode(9);
ListNode l23=new ListNode(2);
l21.next=l22;
l22.next=l23;
System.out.println(addTwoNumbers(l11,l21));
}

public static int addTwoNumbers(ListNode l1, ListNode l2) {
int sum=0;
StringBuilder sb1=new StringBuilder();
StringBuilder sb2=new StringBuilder();
int flag=0; //记录有几个节点
while(l1!=null){
sb1.append(l1.val);
l1=l1.next;
flag++; //记录有几个节点
}
while(l2!=null){
sb2.append(l2.val);
l2=l2.next;
}
int a=fanzhuan(Integer.parseInt(String.valueOf(sb1)));
int b=fanzhuan(Integer.parseInt(String.valueOf(sb2)));
System.out.println(a+" "+b);
return a+b;
}


//自定义数字反转函数 617->716
public static int fanzhuan(int n){
StringBuilder sb3=new StringBuilder();
int m=1;
while (n!=0){
sb3.append(n%10);
n=n/10;
}
return Integer.parseInt(String.valueOf(sb3)); //字符串转int正数
}

}

结果


面试16.01 交换数字(中间值/数组交换)

题目

分析

1. 使用temp中间值(循环给)
        temp=a;  //a的值给temp
        a=b;     //b的值给a(a已经给temp)
        b=temp;  //temp的值给b(b已经给a)

2. 不适用temp中间值
        数组交换

代码

1
2
3
4
5
6
7
8
class Solution {
public int[] swapNumbers(int[] numbers) {
int[] a=new int[2];
a[0]=numbers[1]; //原来第二个数到第一个
a[1]=numbers[0]; //原来第一个数到第二个
return a;
}
}

结果


面试16.05 阶乘尾数(大数乘法/5的因数)

题目

分析

1. 先计算出阶乘的值 然后按位输出判断0的个数
2. 判断5的因数个数(多少个数字能整除5)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class JieChengWeiShu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(trailingZeroes(n));
}

public static int trailingZeroes(int n) {
int ans=0;
while(n>0){
ans+=n/5; //不断的/5求次数
n/=5;
}
return ans;
}

}

结果


面试17.06 2出现的次数(取每位值)

题目

分析

1.思路:通过每一个数循环去拆开这个数得到2的个数最后综合结果

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class ErCiShu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int jie=0;
for(int i=1;i<=n;i++){ //从1到n都调用方法得到结果
jie+=numberOf2sInRange(i);
}
System.out.println(jie);
}

public static int numberOf2sInRange(int n) {
int ci=0; //记录2的个数
int m=1;
while (n != 0) {
m = n % 10;
if (m == 2) {
ci++; //每一位是2就ci++计数
}
n = n / 10;
}
return ci;
}

}

结果


面试17.09 第K个数(看是加3/5/7哪个)

题目

分析

以1 3 5 7 9序列为例:
    1. 第一轮找i=1下标 dp[1]=min(dp[0]*3,dp[0]*5,dp[0]*7)最后选3 p3指针后移到1
    2. 第二轮找i=2下标 dp[2]=min(dp[1]*3,dp[0]*5,dp[0]*7)最后选5 p5指针后移到1

注:其实就是不断地加3/5/7 看到底加哪个最近最好依次上升 

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DiKShu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(getKthMagicNumber(n));
}

public static int getKthMagicNumber(int k) {
int p3=0,p5=0,p7=0;
int[] dp=new int[k];
dp[0]=1; //第一个数一定是1
for(int i=1;i<k;i++){
dp[i]=Math.min(dp[p3]*3,Math.min(dp[p5]*5,dp[p7]*7)); //当前值肯定是离上一个最近的(找最小的)
//匹配到是哪一个就将对应指针后移 方便后面计算该多少个3/5/7
if(dp[i]==dp[p3]*3){
p3++;
}
if(dp[i]==dp[p5]*5) {
p5++;
}
if(dp[i]==dp[p7]*7) {
p7++;
}
}
return dp[k-1]; //返回数组最后一位
}

}

结果


面试14-I 剪绳子/整数拆分(分情况讨论)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class JianShengZi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(cuttingRope(n));
}

public static int cuttingRope(int n) {
if(n <= 3) {
return n - 1; //必须剪出一段长度为1的绳子
}
int a=n/3;
int b=n%3; //n=3a*b
if(b==0){
return (int)Math.pow(3, a); //3的a次方
}
if(b==1){
return (int)Math.pow(3, a - 1) * 4;
}
return (int)Math.pow(3, a) * 2; // 3 3 5(45) <<< 3 4 4(3*4*4=48)
}

}

结果


面试14-II 剪绳子(分情况讨论)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int b = n % 3, p = 1000000007;
long rem = 1, x = 3;
for(int a = n / 3 - 1; a > 0; a /= 2) {
if(a % 2 == 1) rem = (rem * x) % p;
x = (x * x) % p;
}
if(b == 0) return (int)(rem * 3 % p);
if(b == 1) return (int)(rem * 4 % p);
return (int)(rem * 6 % p);
}
}

结果


面试17.打印从1到最大的n位数(StringBuilder得最大值)

题目

分析

1. 通过StringBuilder对象获得最大值max
2. 通过Integer.parseInt(String.valueOf(sb))将字符串转整数
3. 最后通过循环将值导入数组输出数组

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface YiDaoN {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(Arrays.toString(printNumbers(n)));
}

public static int[] printNumbers(int n) {
StringBuilder sb=new StringBuilder();
while(n--!=0){
sb.append("9"); //不停地贴9
}
int max=Integer.parseInt(String.valueOf(sb)); //字符串转为整数int
int[] a=new int[max];
for(int i=0;i<max;i++){
a[i]=i+1;
}
return a;
}

}

结果


面试43 1-n整数中1出现的次数/数字1的个数(拆开求1个数)

题目

分析

和之前的求2的出现次数一样我每次每个数去拆开求解每一次出现1的次数即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Yi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int jie=0;
for(int i=1;i<=n;i++){ //从1到n都调用方法得到结果
jie+=numberOf2sInRange(i);
}
System.out.println(jie);
}

public static int numberOf2sInRange(int n) {
int ci=0; //记录1的个数
int m=1;
while (n != 0) {
m = n % 10;
if (m == 1) {
ci++; //每一位是1就ci++计数
}
n = n / 10;
}
return ci;
}

}

结果


面试44.数字序列中某一位的数字/第N个数

题目

分析

代码

1
2


结果


面试49.丑数(三指针分析)

题目

分析

1. 和只能包含3/5/7因子的题目一样
2. 指定p2 p3 p5三个指针只能进行乘对应数字,每次去判断最小的放入对应数组位置,然后将对应指针后移用于下轮判断

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ChouShu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(nthUglyNumber(n));
}

public static int nthUglyNumber(int n) {
int[] a=new int[n];
a[0]=1;
int p2=0;
int p3=0;
int p5=0;
for(int i=1;i<n;i++){
a[i]=Math.min(a[p2]*2,Math.min(a[p3]*3,a[p5]*5)); //就看哪个乘最小 放入当前位置
if(a[i]==a[p2]*2){
p2++; //哪个满足就要指针后移 为了下轮的判断
}
if(a[i]==a[p3]*3){
p3++;
}
if(a[i]==a[p5]*5){
p5++;
}
}

return a[n-1];
}

}

结果


素数(筛法)

题目

找到1-n之间的所有素数

分析

1. 定义一个布尔数组res(大小就是n+1)
2. 将所有值都先赋成true(后面不是的话要改为false)
3. 第一层循环从i=2到i=n/i遍历
4. 如果第一层的res[i]位置是true说明就是素数,找到对应的倍数改为false
5. 第二层循环从2 3 4这样的倍数去乘让对应位置变false

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt(); //输入要判断的多大值
find(n); //调用方法返回结果
}

public static void find(int n){
boolean[] res=new boolean[n+1];
for(int i=0;i<res.length;i++){
res[i]=true;
}
for(int i=2;i<=n/i;i++){ //从2 3 4 5开始
if(res[i]){ //如果i这个位置是true说明是素数
for (int j=i;j<=n/i;j++) { //从i的1倍 2倍 3倍开始
res[i*j]=false;
}
}
}
for(int i=2;i<res.length;i++){ //从第二位开始输出 (0和1都不是素数)
if(res[i]){
System.out.print(i+" "); //输出素数
}
}
}

}

结果


16进制转10进制

分析

1. 将字符串转大写[toUpperCase()方法]之后分隔成字符数组[toCharArray()方法]
2. 倒序遍历这样方便计算每一次16的倍数[利用math的pow函数解决]
3. 判读就使用Character类的isDigit和isUpperCase判断是不是大写字母和数字,然后根据res=res原来的值+当前值*16的倍数
4. 最后结果是double需要转int即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.nextLine();
System.out.println(zhuan(s));
}

public static int zhuan(String s){
char[] c=s.toUpperCase().toCharArray(); //字符串全转为大写之后拆开 假设输入AbC --> [A,B,C]
double res=0; //最后接结果
int flag=0; //控制每次应该乘多少个16
for(int i=c.length-1;i>=0;i--){ //倒序方便利用flag计算当前位置是16的几次方
char temp=c[i]; //获取当前值
if(Character.isUpperCase(temp)){
if(temp>='A'&&temp<='F'){
res=(temp-'A'+10)*Math.pow(16.0,(double)(flag++))+res; //当前的字母对应的数字*16的倍数+之前的值
}else{
System.out.println("false!"); //出现的字符不在A-F之间
}
}else if(Character.isDigit(temp)){ //出现是0-9的范围内
res=res+(int)(temp-48)*Math.pow(16.0,(double)(flag++)); //当前的字母对应的数字*16的倍数+之前的值
}
}
return (int)res; //因为使用pow函数返回值是double 最后我们需要转为int
}

}

结果


10进制转16进制

分析

1. 就跟10进制转2进制一样
2. 不断地n/16拆分 每一个余数n%16就是结果集(但是要反序)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt(); //输入10进制
System.out.println(find(n));
}

public static String find(int n){
StringBuilder sb=new StringBuilder();
//就跟10进制转2进制一样(直到10进制的数字拆为0结束)
while(n!=0){
int temp=n%16; //获取每一次的余数(要拼接的数字 只不过要反序)
//是普通的0-9的数字
if(temp>=0&&temp<=9){
sb.append(temp); //直接填进去
}else if(temp>=10&&temp<=15){
sb.append((char)(temp-10+'a')); //是10-15的范围内 需要转为a-f
}
else{
System.out.println("false"); //不符合16进制的要求
break;
}
n=n/16; //不断将数字拆小
}
return sb.reverse().toString(); //倒序粘贴在一起才是最终答案
}

}

结果


旅行终点站(找某个路径的终点不是其他的起点)

题目

分析

1.思路: 如果某个路径的终点不是另一个路径的起点,则该点就是旅行终点.
2.实现: 
    2.1 使用map存储所有路径的出发点[path.get(0)]
    2.2 判断set里面没有哪个get(1)的值就说明是终点

代码

1
2
3
4
5
6
7
8
9
10
11
12
13

public String destCity(List<List<String>> paths) {
HashSet<String> set = new HashSet<>();
for (List<String> path : paths) {
set.add(path.get(0)); //所有出发点放入set
}
for (List<String> path : paths) {
if (!set.contains(path.get(1))) { //如果某个终点没有在出发点集合中 说明就是终点
return path.get(1); //返回终点即可
}
}
return null;
}

实现


汉明距离(异或性质/布赖恩·克尼根算法)

题目

分析

1. 其实就是两个数字变二进制,找二进制不同的两个位置之间距离
2. 使用异或的性质:相同为0不同为1
3. 执行步骤:
    1. 先将x和y异或之后的结果 只要找到这个结果出现1的位置就说明是两个数不同的位置
    2. 不断变小,不断判断%2是否为1记录距离

https://leetcode-cn.com/problems/hamming-distance/solution/yi-ming-ju-chi-by-leetcode/

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println(hammingDistance(1,4));
}

public static int hammingDistance(int x, int y) {
int xor = x ^ y; // 0001异或0100 --> 0101就是5
System.out.println("异或结果"+xor);
int distance = 0; //测量距离
while (xor != 0) {
if (xor % 2 == 1) //不同的话就是异或的结果为1的地方
distance += 1;
xor = xor /2; //变小
}
return distance; //返回距离
}

}

结果


增减字符串匹配(双指针移动)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public static int[] diStringMatch(String s) {
int n=s.length(); //获取字符串长度n
int[] res=new int[n+1]; //结果长为n+1
//确定左右指针
int left=0;
int right=n;
for (int i = 0; i < n; i++) {
char temp = s.charAt(i); //获取字符串当前字符
if (temp == 'I') { //递增
res[i]=left++;
}
if (temp == 'D') { //递减
res[i]=right--;
}
}
res[n]=left; //最后一个n+1的位置没有判断 添加left进去
return res;
}

结果


最长特殊序列I(判断字符串长度)

题目

分析

代码

1
2
3
4
5
6

public int findLUSlength(String a, String b) {
if (a.equals(b))
return -1; //如果两个字符串相同 返回-1
return Math.max(a.length(), b.length()); //如果不相同就看谁的更长度更长了
}

结果


非递增顺序的最小子序列(数学问题)

题目

分析

1. 其实就是找一段序列是大于总和/2的
2. 存的话就用list集合存
3. 先排序之后倒序遍历插入找即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public List<Integer> minSubsequence(int[] nums) {
Arrays.sort(nums); //排序
int left=0; //左指针
int right=nums.length-1; //右指针
int sum=0, sum_right=0;
for(int i=0; i<nums.length; i++){
sum += nums[i]; //求总和sum
}
List<Integer> ans = new ArrayList<>(); //接住结果
while(sum_right <= sum/2){
ans.add(nums[right]);
sum_right += nums[right]; //倒序相加 超过总和的一半就弹出
left++;
right--;
}
return ans; //返回结果
}

结果


换酒问题(不断缩小)

题目

分析

1. 其实很像进制转换,不过需要考虑换完之后要加上换了的数量
2. 只要sum剩下的酒瓶 < 要兑换的酒瓶就弹出

代码

1
2
3
4
5
6
7
8
9
10
11
12
13

public int numWaterBottles(int sum, int numExchange) {
int total = sum; //首先将sum加入
while (sum >= numExchange) { //手里的酒瓶数 < 要兑换酒瓶数量
//change表示的是兑换成酒的数量
int change = sum / numExchange;
//total再加上兑换的酒
total += change;
//瓶子数量变为兑换成酒的数量加上没有兑换成酒的数量
sum = change + sum % numExchange; //更新手里的总数
}
return total;
}

结果


托普利茨矩阵(斜对角线数唯一)

题目

分析

1. 斜对角线hang-lie肯定是相同的,使用map存入第一个要判断的,然后对比后面的每一个hang-lie
2. 从1,1开始判断hang-1,lie-1的是否相同

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//第一种 每一个斜对角线的hang-lie是相同的
// 将第一个hang-lie的元素存入map 后面判断错误返回false
public boolean isToeplitzMatrix(int[][] matrix) {
Map<Integer, Integer> groups = new HashMap();
for (int r = 0; r < matrix.length; ++r) {
for (int c = 0; c < matrix[0].length; ++c) {
if (!groups.containsKey(r-c))
groups.put(r-c, matrix[r][c]);
else if (groups.get(r-c) != matrix[r][c])
return false; //
}
}
return true;
}


//第二种 从(1,1)开始只是对照上一层的(i-1,j-1)元素
public boolean isToeplitzMatrix(int[][] matrix) {
int column = matrix[0].length;
for (int i = 1; i < matrix.length; i++) {
for (int j = 1; j < column; j++) {
if (matrix[i][j] != matrix[i - 1][j - 1])
return false; //如果不同就弹出false
}
}
return true;
}

结果


最小移动次数使数组元素相等

题目

分析

1. 每次使n-1个元素+1 == 每次使1个元素-1然后所有元素+1
2. 所以只需要找到:每次让1个元素-1,多少次后让所有元素相等

代码

1
2
3
4
5
6
7
8
9
10

public static int minMoves(int[] a) {
Arrays.sort(a); //对a数组进行排序
int res=0;
int count=a.length-1; //每次能够使n-1个元素增加1
for (int i = 0; i < a.length; i++) {
res+=a[i]-a[0]; //计算比a【0】多多少
}
return res;
}

结果


LeetCode递归

面试08.05 递归乘法(乘法变加法)

题目

分析

1. 不需要乘法的话我就进行多次加法进行操作

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ChengFa {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int a=input.nextInt();
int b=input.nextInt();
System.out.println(multiply(a,b));
}

public static int multiply(int a, int b) {
int sum=0;
for(int i=0;i<b;i++){
sum+=a; //乘法就相当于多次加法
}
return sum;
}

}

结果


面试08.06 汉诺塔(递归)

题目

分析

1. n=1 : 直接将a移除一个到c
2. n!=1: 先a通过c到b 然后b通过a到c(中间a移除一个到c)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class HanNuoTa {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
List<Integer> A=new ArrayList<>();
A.add(2);
A.add(1);
A.add(0);
List<Integer> B=new ArrayList<>();
List<Integer> C=new ArrayList<>();
hanota(A,B,C);
System.out.println(C.toString());
}

public static void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
hanota(A.size(),A,B,C);
}
//总体的思路:要把A的n个盘移到C上,首先要借助B把n-1个盘移开,然后把A最下面的最大的移到C
//然后把B的n-1个盘移到C上,按照同样的逻辑
//这个函数的意思就是将A的n个盘移到C上
public static void hanota(int n,List<Integer> A, List<Integer> B, List<Integer> C){
//如果A上只有一个盘,直接移到C上
if(n==1) {
C.add(A.remove(A.size()-1));
return;
}
//如果不是,借助c将N-1个盘移到B上
hanota(n-1,A,C,B);
//然后把剩下的一个移到C
C.add(A.remove(A.size()-1));
//把B的移到C上
hanota(n-1,B,A,C);
}

}

结果


面试16.11 跳水板(等差数列)

题目

分析

1. 假设是最短是1 最长是2 有k=3个模板求结果。
2. 取值就是 111 112 122 222(中间每次差了2-1的值),取值的个数就是k+1个。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class TiaoShuiBan {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int shorter=input.nextInt();
int longer=input.nextInt();
int k=input.nextInt();
System.out.println(Arrays.toString(divingBoard(shorter,longer,k)));
}

public static int[] divingBoard(int shorter, int longer, int k) {
// 最小值
int min = shorter * k; //就是可能性中最小取值
// 最大值
int max = longer * k; //就是可能性中最大取值
// 差值
int difference = longer - shorter; //每一次可能中差的一次结果
//数组长度
int len=0;
if (k != 0) {
if (difference == 0) { //最长和最短一样: 可能性就只有一种
len = 1;
} else {
len = k+1; // 最长和最短不一样: 长度是k+1
}
}

int[] nums = new int[len]; //存放可能性的值
for (int i = 0; i <len; i++) {
if (i == 0) {
nums[i] = min; //最小的可能就是k次都是最短的
} else {
nums[i] = nums[i-1] + difference; //后面的每一次可能就是前面的加上两者差
}
}
return nums;
}

}

结果


面试17.12 BiNode

题目

分析

代码

1
2


结果


面试10-I 斐波那契数列(递归/动态规划)

题目

分析

1. 递归:return fib(n-1)+fib(n-2)
2. 动态规划:就是abc三个数字不断后移
    sum = (a + b) % 1000000007;  //第三个数字
    a = b;    //原来的第二个是下一轮的第一个
    b = sum;  //原来的第三个是下一轮的第二个

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class FeiBo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println("递归:"+fib(n));
System.out.println("动态规划:"+dongtai(n));
}
//递归
public static int fib(int n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
return fib(n-1)+fib(n-2);
}
//动态规划
public static int dongtai(int n) {
int a = 0, b = 1, sum;
for(int i = 0; i < n; i++){
sum = (a + b) % 1000000007;
a = b;
b = sum;
}
return a;
}

}

结果


面试10-II 青蛙跳台阶(递归/动态规划)

题目

分析

1. 和斐波那契数列一样!!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class QingWa {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(numWays(n));
System.out.println(numWayser(n));
}

//递归
public static int numWays(int n) {
if(n==1){
return 1; //1
}
if(n==2){
return 2; // 11/2
}
return numWays(n-1)+numWays(n-2);
}

//动态规划
public static int numWayser(int n) {
int a=1;
int b=2;
int c=0;
for(int i=1;i<n;i++){
c=(a+b)%1000000007;
a=b;
b=c;
}
return a;
}

}

结果


面试16. 数值的整数次方(分析特殊情况)

题目

分析

1. 底为0结果就是0
2. 指为0结果就是1
3. 底不为0指数是正数(>1)  正常for循环计算
4. 底不为0指数是负数  先负数转正数后for循环计算

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ShuZhengCiFang {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Double x=input.nextDouble();
int n=input.nextInt();
System.out.printf("%.5f",cifang(x,n));
}

public static double cifang(double base,int exponent){
double c=1;
//底为0
if(base==0){
return 0;
}
if(exponent==0){ //任何数的0次方都是1
return 1;
}
//底不为0 指数是负数
if(exponent<0){
exponent=-exponent;
while (exponent--!=0) { //有多少m就乘多少次n
c*=base; //c=c*n 在前面的基础上乘n
}
c=1.0/c; //取倒数
}
//底不为o 指数大于等于1
if(exponent>=1) {
while (exponent--!=0) { //有多少m就乘多少次n
c*=base; //c=c*n 在前面的基础上乘n
}
}
return c;
}

}

结果


生成最小高度树(递归)

题目

分析

1. 使用递归法解决
2. 因为要高度最小所以尽量左右子树要多,所以选数组中间元素为根节点
3. 然后生成根节点n,n的值为数组中间节点
4. n的左节点为递归调用(0--nums.length/2)
5. n的右节点为递归调用(nums.length/2+1--nums.length)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13

class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if(nums.length==0) {
return null; //数组为空
}
TreeNode n = new TreeNode(nums[nums.length/2]); //取最中间的值作为根节点
//使用Arrays.copyOfRange()方法进行递归
n.left = sortedArrayToBST(Arrays.copyOfRange(nums,0,nums.length/2));
n.right = sortedArrayToBST(Arrays.copyOfRange(nums,nums.length/2+1,nums.length));
return n; //返回n节点
}
}

结果


二叉搜索树范围和(深度优先遍历)

题目

分析

https://leetcode-cn.com/problems/range-sum-of-bst/solution/hua-jie-suan-fa-938-er-cha-sou-suo-shu-de-fan-wei-/

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14

public static int rangeSumBST(TreeNode root, int L, int R) {
if(root==null){ //为空
return 0;
}
if(root.val<L){
return rangeSumBST(root.right,L,R); //当前节点<L 返回右子树之和
}
if(root.val>R){
return rangeSumBST(root.left,L,R); //当前节点>R 返回左子树之和
}
//当前节点值+左子树之和+右子树之和
return root.val + rangeSumBST(root.left, L, R) + rangeSumBST(root.right, L, R);
}

结果


单值二叉树

题目

分析

1. 左子树和根节点不同 返回fasle
2. 右子树和根节点不同 返回false
3. 递归return返回 左子树&&右子树

代码

1
2
3
4
5
6
7
8
9
10
11
12
13

public boolean isUnivalTree(TreeNode root) {
if (root == null) {
return true; //空树就是true
}
if (root.left != null && root.val != root.left.val) { //左树不为空 && 根节点值!=左子树节点
return false;
}
if(root.right != null && root.val != root.right.val) { //右树不为空 && 根节点值!=右子树节点
return false;
}
return isUnivalTree(root.left) && isUnivalTree(root.right); //递归分析左右节点
}

结果


各位相加(递归)

题目

分析

1. 使用进制取每一位增加给temp,然后递归找到temp<10就弹出

代码

1
2
3
4
5
6
7
8
9
10
11
12

public int addDigits(int num) {
if (num < 10) {
return num; //如果是小于10的值就返回
}
int temp = 0;
while (num != 0) {
temp=temp+num%10; //每一位增加
num/=10; //数组缩小
}
return addDigits(temp); //递归找temp
}

结果


数字翻译成字符串(递归)

题目

分析

1. 这道题其实就是一个递归:递归出口是num是只有一位数,
2. 以xyzcba为例,先取最后两位(个位和十位)即ba,
    2.1 如果ba>=26,必然不能分解成f(xyzcb)+f(xyzc),此时只能分解成f(xyzcb);
    2.2 但还有一种情况,就是ba<=9,也就是该数十位上为0,此时只能分解成f(xyzcb);

代码

1
2
3
4
5
6
7
8
9
10
11
12
13

public int translateNum(int num) { //递归
if (num<=9) {
return 1; //最后num是个位数小于等于9
}
//xyzcba为例
int ba = num%100; //取最后两位
if (ba<=9||ba>=26) {
return translateNum(num/10); //如果ba>=26,必然不能分解成f(xyzcb)+f(xyzc),此时只能分解成f(xyzcb)
//但还有一种情况,就是ba<=9,也就是该数十位上为0 也只能分解成f(xyzcb)
}
return translateNum(num/10)+translateNum(num/100); //其他情况下就是最后一位和倒数第二位
}

结果


#

LeetCode排序

面试16.16 部分排序(排序后找不同的两边下标)

题目

分析

1. a.clone()复制一个数组然后排序
2. 最左边不同的值和最右边不同的值就是要求的两边

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class BuFenPaiXu {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(Arrays.toString(subSort(a)));
}

public static int[] subSort(int[] a) {
int[] b=a.clone(); //复制一个a数组
int[] jie=new int[]{-1,-1}; //结果的值默认是-1 -1
Arrays.sort(b); //对于b数组进行排序
//从左到右找最左边的不同的值
for(int i=0;i<a.length;i++){
if(a[i]!=b[i]){
jie[0]=i;
break;
}
}
//如果找不到就输出 -1 -1
if(jie[0]<0){
return jie;
}
//从右到左找最右边的不同的值
for(int i=a.length-1;i>=0;i--){
if(a[i]!=b[i]){
jie[1]=i;
break;
}
}
return jie;
}

}

结果


面试16.21 交换和(set去重)

题目

分析

1. 两数组间差要是偶数(偶数才可以补之间差)
2. 计算出两者差cha=sum1—sum2
3. 计算出两者平均要补aver=cha/2
4. 使用set存储数组a,然后进行去重set.contains(b[i]+aver)是否存在就说明两者之间可以互换!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class JiaoHuanHe {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int m=input.nextInt();
int[] a=new int[n];
int[] b=new int[m];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
for(int i=0;i<m;i++){
b[i]=input.nextInt();
}
System.out.println(Arrays.toString(findSwapValues(a,b)));
}

public static int[] findSwapValues(int[] a, int[] b) {
int sum1 = 0; //a数组的和
int sum2 = 0; //b数组的和
Set<Integer> set = new HashSet<>();
//遍历获得a数组的和
for(int num:a){
sum1 += num;
set.add(num); //将a数组的内容加到set集合
}
//遍历获得b数组的和
for(int num:b) {
sum2 += num;
}
int diff = sum1 - sum2; //获取之间的差
if(diff % 2 != 0) {
return new int[]{}; //如果差不是偶数的话肯定不能找到
}
int target = diff / 2; //中间差/2就是两边需要补的数字
for(int num:b){
if(set.contains(num + target)){ //如果a数组里面有b数组加上中间补的数字 说明可以互换
return new int[]{num + target, num}; //反着输出
}
}
return new int[]{}; //返回空
}

}

结果


面试17.08 马戏团人塔(map/最长子序列)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Solution {
public int bestSeqAtIndex(int[] height, int[] weight) {
if (height.length <= 1) {
return height.length;
}

Integer[] indexs = new Integer[height.length];
for (int i = 0; i < indexs.length; i++) {
indexs[i] = i;
}

Arrays.sort(indexs, (o1, o2) -> {
if (height[o1] == height[o2]) {
return weight[o2] - weight[o1];
}
return height[o1] - height[o2];
});

int[] tail = new int[height.length + 1];
int end = 0;
tail[0] = weight[indexs[0]];
for (int i = 1; i < height.length; i++) {
if (weight[indexs[i]] > tail[end]) {
++end;
tail[end] = weight[indexs[i]];
} else {
int left = 0;
int right = end;
int target = weight[indexs[i]];
while (left < right) {
int mid = (left + right) >>> 1;
if (target > tail[mid]) {
left = mid + 1;
} else {
right = mid;
}
}
tail[left] = target;
}
}
// 因为是从0 开始的 所以需要加1
end++;
return end;
}

结果


面试17.14 最小k个数(Arrays.sort())

题目

分析

1. 使用数组排序之后输出前k位即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MinK {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
int k=input.nextInt();
System.out.println(Arrays.toString(smallestK(a,k)));
}

public static int[] smallestK(int[] arr, int k) {
Arrays.sort(arr); //原数组进行排序
int[] b=new int[k];
for(int i=0;i<k;i++){
b[i]=arr[i]; //前k个数给b数组并且输出
}
return b;
}

}

结果


面试45 数组排成最小的数(sort内置函数)

题目

分析

主要使用内置函数:Arrays.sort(strs,(x,y)->(x+y).compareTo(y+x))

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class PaiZuiXiao {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(minNumber(a));
}

public static String minNumber(int[] nums) {
StringBuilder sb=new StringBuilder();
String[] strs=new String[nums.length];
for(int i=0;i<strs.length;i++){
strs[i]=String.valueOf(nums[i]); ///所有数字转为字符串
}
Arrays.sort(strs,(x,y)->(x+y).compareTo(y+x)); //内置函数比较排序
for(String s:strs){
sb.append(s); //按序将所有内容添加到sb对象内
}
return sb.toString();
}

}

结果


LeetCode字符串

面试01.03 URL化(空格替换)

题目

分析

1. string.substring(x,y).replaceAll("x","y"):
2. StringBuilder.append("X")
3. 字符数组char[]

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class URLhua {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
int length=input.nextInt();
System.out.println(replaceSpaces(s,length));
}

public static char[] replaceSpaces(String s, int length) {
char[] a=new char[length*3];
int i=0;
char c;
for(int j=0;j<length;j++) { //控制长度length
c=s.charAt(j); //获取字符串的当前字符
if (c == ' '){ //如果当前位置为空
a[i++] = '%'; //空替换为 %20
a[i++] = '2';
a[i++] = '0';
}else{
a[i++] =c; //不为空就它填进去
}
}
return a;
}

}

结果


面试01.04 回文排列(字符出现次数)

题目

分析

每个字符出现的次数为偶数 / 有且只有一个字符出现的次数为奇数

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class HuiWenPaiLie {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.next();
System.out.println(canPermutePalindrome(s));
}

public static boolean canPermutePalindrome(String s) {
Set<Character> set = new HashSet<>();
for(char c:s.toCharArray()) {
if (!set.add(c)) { //如果c字符不能添加就说明是重复出现
set.remove(c); //移除第一次添加的c字符
}
}
return set.size()<=1; //看最后是不是只有那个奇数的一个/全是偶数的被移除了
}

}

结果


面试01.05 一次编辑(统计变换次数)

题目

分析

1. |a.length-b.length|>1 说明不可能通过一次编译完成
2. 两层循环如果到了不相等的位置
3. 判断是前面的多一个还是后面的多一个
    3.1 前面多 后面的字符串需要多添一个(j--)
    3.2 后面多 前面的字符串需要多添一个(i--)
    3.3 最后一次执行count--
4. 最后我们通过判断count变化几次来判断

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class YiCiBianYi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String first=input.nextLine();
String second=input.nextLine();
System.out.println(oneEditAway(first,second));
}

public static boolean oneEditAway(String first, String second) {
int len=first.length()-second.length();
if(len>1||len<-1){
return false; //长度差大于1 肯定不可能
}
int count=1;
for(int i=0,j=0;i<first.length()&&j< second.length();i++,j++){
if(first.charAt(i)!=second.charAt(j)){
if(len==1){ //前面的多一个
j--; //second要不要添加一个字符
}else if(len==-1){ //后面的多一个
i--; //first要不要添加一个字符
}
count--; //反正不相等肯定要操作一次 count--变成0
}
if(count<0){ //最多能改一次(最大也是0)
return false;
}
}
return true;
}

}

结果


面试01.06 字符串压缩(StringBuilder添加)

题目

分析

1. 使用StringBuilder字符串对象sb
2. 步骤:
    2.1 当前字符添加进去
    2.2 计算出现次数
        2.2.1 相邻相等计数器++
        2.2.2 相邻不相等直接break
    2.3 将重复次数添加进去
    2.4 返回长度最小的结果(s/sb)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class StringYaSuo {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
System.out.println(compressString(s));

}

public static String compressString(String s) {
StringBuilder sb=new StringBuilder(); //新建sb对象
for(int i=0;i<s.length();i++){
int count=1; //记录重复出现次数
char c=s.charAt(i); //获取当前字符串的字符
sb.append(c); //将其加入到sb对象
for(int j=i+1;j<s.length();j++){ //找后面的用于判断是否相同count++?
char c2=s.charAt(j); //获取当前字符串的字符(c之后一位)
if(c==c2){ //如果前后一样 就count++
count++;
i++; //成功了就一定要记得往后推!!!!!!!!
}else{
break; //如果不相等 说明重复结束了
}
}
sb.append(count); //循环之后我们将重复次数加进去
}
return s.length()>sb.length()?sb.toString():s;
}

}

结果


面试01.09 字符串轮转(contains判断是否包含子串)

题目

分析

1. 原来的s1重复添加(S1+=S1;)
2. 使用String.contains(s2); //判断现在的s1里面有没有s2

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class StringLunZhuan {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s1=input.nextLine();
String s2=input.nextLine();
System.out.println(isFlipedString(s1,s2));
}

public static boolean isFlipedString(String s1, String s2) {
if(s1.length()!=s2.length()){ //如果不一样长肯定有问题
return false;
}
if(s1.equals(s2)){ //如果是aaa这种肯定是正确
return true;
}
s1+=s1; //将s1重复添加一次(abc+abc=abcabc)
return s1.contains(s2); //查找s1里面有没有s2
}

}

结果


面试05.02 二进制转字符串(StringBuilder添加)

题目

分析

1. 只需要考虑小数点后的乘2问题
2. 思路:每次乘2将整数部分按需存进去直到乘2为0

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ErjinzhizhuanString {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Double num=input.nextDouble();
System.out.println(printBin(num));
}

public static String printBin(double num) {
if(num <= 0 || num >= 1){
return "ERROR";
}
StringBuilder sb = new StringBuilder(); //用于粘贴结果
sb.append("0."); //因为介于0-1之间
while(num != 0){
num *= 2;
sb.append(num - 1 >= 0 ? 1 : 0);
if(num >= 1){
num --;
}
if(sb.length() > 32){
return "ERROR";
}
}
return sb.toString();
}

}

结果


面试08.09 括号(深度优先遍历(回溯))

题目

分析

https://leetcode-cn.com/problems/generate-parentheses/solution/hui-su-suan-fa-by-liweiwei1419/

深度优先遍历(回溯):

  • 以n=2为例:

画图以后,可以分析出的结论:

1. 当前左右括号都有大于 00 个可以使用的时候,才产生分支;

2. 产生左分支的时候,只看当前是否还有左括号可以使用;

3. 产生右分支的时候,还受到左分支的限制,右边剩余可以使用的括号数量一定得在严格大于左边剩余的数量的时候,才可以产生分支;

4. 在左边和右边剩余的括号数都等于 00 的时候结算。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class KuoHao {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n=input.nextInt();
System.out.println(generateParenthesis(n)); //调用方法
}

public static List<String> generateParenthesis(int n) {
List<String> res=new ArrayList();
//特定判断
if (n == 0) {
return res;
}
//执行深度优先遍历
dfs("",n,n,res);

return res;
}

/**
* @param curStr 当前递归得到的结果
* @param left 左括号还有几个可以使用
* @param right 右括号还有几个可以使用
* @param res 结果集
*/
private static void dfs(String curStr, int left, int right, List<String> res) {
//因为每一次尝试,都使用新的字符串变量,所以无需回溯
if(left==0&&right==0){
res.add(curStr); // 在递归终止的时候,直接把它添加到结果集即可
return ; //void不需要返回
}

// 剪枝(左<右就符合左边用的多这样不需要剪枝)
if (left > right) {
return; //void不需要返回
}

//左分支(左边用了一个“(”)
if(left>0){
dfs(curStr+"(", left-1, right, res);
}

//右分支(右边用了一个“)”)
if(right>0){
dfs(curStr+")", left, right-1, res);
}

}

}

结果


面试16.18 模式匹配(KMP)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Solution {
private char[] global_pattern, global_value;
private int value_len;

public boolean patternMatching(String pattern, String value) {
value_len = value.length();
if (value_len == 0) return pattern.length() < 2;
global_pattern = pattern.toCharArray();
global_value = value.toCharArray();
int pattern_len = pattern.length();
if (pattern_len == 0) return false;
int count_a = 0, count_b = 0;
for (char ch : global_pattern) {
if (ch == 'a') ++count_a;
else ++count_b;
}
if (count_a == 0) return single_count(count_b);
if (count_b == 0) return single_count(count_a);
return count_a < count_b ? muti_count(count_a, count_b, 'a') : muti_count(count_b, count_a, 'b');
}

private boolean single_count(int count) {
if (value_len % count != 0) return false;
String base = new String(global_value, 0, value_len / count);
int base_len = base.length(), idx = base_len;
while (idx < value_len) {
if (!check(base, idx)) return false;
idx += base_len;
}
return true;
}

private boolean muti_count(int small_count, int big_count, char small_ch) {
int small_sum = 0;
search:
while ((small_sum += small_count) < value_len) {
int remain = value_len - small_sum;
if (remain % big_count != 0) continue;
int big_len = remain / big_count, small_len = small_sum / small_count;
String small_str = null, big_str = null;
int value_idx = 0;
for (char cur_ch : global_pattern) {
if (cur_ch == small_ch) {
if (small_str == null)
small_str = new String(global_value, value_idx, small_len);
else if (!check(small_str, value_idx)) continue search;
value_idx += small_len;
} else {
if (big_str == null)
big_str = new String(global_value, value_idx, big_len);
else if (!check(big_str, value_idx)) continue search;
value_idx += big_len;
}
}
return true;
}
return single_count(small_count) || single_count(big_count);
}

private boolean check(String str, int value_idx) {
int idx = 0;
for (char ch : str.toCharArray())
if (ch != global_value[value_idx + idx++])
return false;
return true;
}
}

结果


面试16.26 计算器(Stack栈)

题目

分析

1. 使用字符数组arr接住字符串s的每一位字符,str接住每一次的数字,num用于将每一次的数字转为int,prev用于接住+-*/,用stack栈进行结果的存放。
2. 对于+-运算直接将数字放入stack栈
3. 对于*/运算需要将结果计算好放入stack栈

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class JiSuanQi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.next();
System.out.println(calculate(s));
}

public static int calculate(String s) {
char[] arr=s.replaceAll(" ","").toCharArray(); //将要判断的字符串转字符数组arr
Stack<Integer> stack=new Stack<>(); //新建stack栈
int res=0; //最终结果
char prev=' '; //每一位字符
for(int i=0;i<arr.length;i++){
StringBuilder str=new StringBuilder();
//1. 每一轮将所对应的数字放到str内!!!!!!!!!!!!
while(i<arr.length&&arr[i]>='0'&&arr[i]<='9'){ //在0-9之内
str.append(arr[i]); //将符合的添加到str
i++; //添加往后挪
}
System.out.println("str的值:"+str.toString());
int num=Integer.parseInt(str.toString()); //假如是3-6-8*5+6/8: num每一次将str中的数字转为int数字
System.out.print("num的值:"+num+" ");
//2. 判断四则运算!!!!!!!!!!!!!!!!!!
if(prev == '+'){
stack.push(num); //将数值放入栈内
}else if(prev == '-'){
stack.push(-num); //将数值相反数放入栈内
}else if(prev == '*'){
stack.push(stack.pop() * num); //乘法算出结果放入栈
}else if(prev == '/'){
stack.push(stack.pop() / num); //除法算出结果放入栈
}else{
stack.push(num);
}
if(i < arr.length) {
prev = arr[i]; //将数组的每一个字符都放入prev内用于判断是不是+-*/中一个
}
}
while (!stack.isEmpty()) { //只要栈不为空
res += stack.pop(); //依次将数组结果弹出后加入到res中
}

return res;
}

}

结果


面试17.13 恢复空格(动态递归+contains包含方法)

题目

分析

1. 使用set集合存储字典内所有单词
2. 定义dp数组每一个位置存放当前最优的答案
3. 定义两层循环:如果set.contains包含方法内有句子中的单词我们就去考虑i当前位置的答案和j位置的答案取最小值

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class HuiFuKongGe {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String[] dictionary={"looked","just","like","her","brother"};
String sentence=input.next();
System.out.println(respace(dictionary,sentence));
}

public static int respace(String[] dictionary, String sentence) {
Set<String> set = new HashSet<>();
for(String str: dictionary) {
set.add(str); //将字典里面的所有单词放入set集合
}
int n = sentence.length(); //获取长度
//dp[i]表示sentence前i个字符所得结果
int[] dp = new int[n+1];
for(int i=1; i<=n; i++){
dp[i] = dp[i-1]+1; //先假设当前字符不在字典
for(int j=0; j<i; j++){
if(set.contains(sentence.substring(j,i))){
dp[i] = Math.min(dp[i], dp[j]); //如果set里面有要判断的单词 就只要最小的长度
}
}
}
return dp[n]; //返回最后一个位置的长度即可
}

}

结果


面试58-I 翻转单词顺序(split()分割/trim()去除首尾空格)

题目

分析

1. 先删除首尾空格然后分割字符串生成一个单词表strs
2. 然后倒序遍历单词表strs存储到StringBuilder对象内

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ZuiChangDanCi {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
System.out.println(reverseWords(s));
}

public static String reverseWords(String s) {
String[] strs = s.trim().split(" "); // 删除首尾空格,分割字符串
StringBuilder res = new StringBuilder();
for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍历单词列表
if(strs[i].equals("")){
continue; // 遇到空单词则跳过
}
res.append(strs[i]+" "); // 将单词拼接至 StringBuilder
}
return res.toString().trim(); // 转化为字符串,删除尾部空格,并返回
}

}

结果


面试58-II 左旋转字符串(substring取特定位置字符串)

题目

分析

1. 使用substring获取n之前的和n之后两部分字符串
2. 然后stringbuilder对象去append链接两个部分

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ZuoXuanZhuanString {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
int n=input.nextInt();
System.out.println(reverseLeftWords(s,n));
}

public static String reverseLeftWords(String s, int n) {
String s1=s.substring(0,n); //前n个长度的字符串
String s2=s.substring(n,s.length()); //后面的正常字符串
StringBuilder sb=new StringBuilder();
sb.append(s2).append(s1); //sb去接s2然后s1
return sb.toString();
}

}

结果


Z字形变换(StringBuilder对象)

题目

分析

参考思路

https://leetcode-cn.com/problems/zigzag-conversion/solution/zzi-xing-bian-huan-by-jyd/

1. 怎么存: 每层都是一个sb对象 最后每一层都append在最终的一个sb对象
2. 怎么上下走: 定义i控制i上下走,上下走就是通过flag的变化(这个操作绝了)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

public class Main {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.next();
int n=input.nextInt();
System.out.println(convert(s,n));
}

public static String convert(String s, int numRows) {
if(numRows<2){ //如果是0行或者1行 就直接输出s即可
return s;
}
//存储每一行的字符(要拼接所以要用StringBuilder类)
List<StringBuilder> rows = new ArrayList<StringBuilder>();
//根据行数每行添加一个StringBuilder
for(int i=0;i<numRows;i++){
rows.add(new StringBuilder()); //每一行都有一个
}
int i=0;
int flag=-1;
for(char c:s.toCharArray()){
rows.get(i).append(c); //对应行添加进去字符
if(i==0||i==numRows-1){
flag=-flag; //到了拐角要变换flag
}
i=i+flag; //1的话就是往下加 -1的话就是往上加
}
StringBuilder res = new StringBuilder(); //新建接住结果
for(StringBuilder row:rows) {
res.append(row); //添加每一行的结果集合
}
return res.toString();//最后记得转字符串
}

}

结果


最常见的单词(map集合去重)

题目

分析

1. 使用正则表达式[^a-z]可以筛选单词
2. 使用map存储出现单词和单词次数
3. 使用remove删除禁用词
4. 使用entrySet()方法取出出现次数最多的单词

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class Solution {
//返回次数最多的单词
public static String mostCommonWord(String s, String[] str) {
s=s.toLowerCase();
String[] temp=s.split("[^a-z]"); //根据空格转字符串

Map<String,Integer> map=new HashMap<>();
for(int i=0;i< temp.length;i++){
String ts=temp[i]; //获取每一个单词的
if(map.containsKey(ts)){
map.put(ts,map.get(ts).intValue()+1); //出现次数+1
}else{
map.put(ts,1); //没出现过就设置出现为1
}
}
for(int i=0;i<str.length;i++){
str[i]=str[i].toLowerCase();
map.remove(str[i]); //依次移除所有的禁用词
}
map.remove("");
Integer max=0;
String res=""; //一定要设置成-1 /0 可能会出错!!!!!!!!!!!
for (Map.Entry<String, Integer> entry : map.entrySet()) {
int count = entry.getValue();
if (count > max) {
max = count;
res = entry.getKey();
}
}
return res;
}
}

结果


字符的最短距离(左右两边最短)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println(Arrays.toString(shortestToChar("loveleetcode",'e')));
}

public static int[] shortestToChar(String S, char C) {
int N = S.length(); //获取字符串长度
int[] ans = new int[N]; //返回结果的ans数组

int prev=Integer.MIN_VALUE/2; //先取负数
//从左往右取结果
for (int i = 0; i < N; ++i) { //正序
if (S.charAt(i) == C) prev = i;
ans[i] = i - prev; //找到相近的字符的距离
}
//从右往左取结果
prev = Integer.MAX_VALUE / 2; //先取正数
for (int i = N-1; i >= 0; --i) { //倒序
if (S.charAt(i) == C) prev = i;
ans[i] = Math.min(ans[i], prev - i); //找到相近的字符的距离
}
return ans; //返回ans数组
}

}

结果


删除回文子序列(因为只有a和b字符)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10

public int removePalindromeSub(String s) {
if ("".equals(s)) {
return 0; //空字符串
}
if (s.equals(new StringBuilder(s).reverse().toString())){
return 1; //本身就是回文串
}
return 2; //其他情况就是一次性删除所有a 然后删除b
}

结果


字符串的最大公因子(辗转相除法)

题目

分析

使用辗转相除法得到最大公因子!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public String gcdOfStrings(String str1, String str2) {
// 假设str1是N个x,str2是M个x,那么str1+str2肯定是等于str2+str1的。
if (!(str1 + str2).equals(str2 + str1)) {
return "";
}
int l1=str1.length();
int l2=str2.length();
// 辗转相除法求gcd。
return str1.substring(0, gcd(l1, l2)); //截取str1的部分字符串
}

public static int gcd(int a, int b) {
return b == 0? a: gcd(b, a % b); //b是0就返回a b不是0就返回a%b
}

结果


仅仅反转字母(字母压栈)

题目

分析

1. 个人感觉倒序输入/反向的都需要栈顶
2. 第一次遍历将所有字符倒序压栈到栈stack  其实就反序放进去
3. 第二次遍历只要是特殊符号就放到遍历的位置  其他位置就反序出栈即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public String reverseOnlyLetters(String S) {
Stack<Character> letters = new Stack();
for (char c: S.toCharArray())
if (Character.isLetter(c))
letters.push(c); //所有数字反序压栈

StringBuilder ans = new StringBuilder();

//第二次再次遍历
for (char c: S.toCharArray()) {
if (Character.isLetter(c))
ans.append(letters.pop()); //如果当前位是字母 就出栈 刚好是反序
else
ans.append(c); //特殊位置继续放入当前位置
}

return ans.toString();
}

结果


翻转数位(只能把1个0改成1)

题目

分析

1. 使用方法将n转成二进制字符串形式s
2. 使用方法将字符串通过0隔开成字符串数组 每个子数组的长度就是1的长度
3. 最后通过for循环遍历找到第哪两个之间+1最大即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static int reverseBits(int n) {
if(n==-1){
return 32; //负数就是32个
}
String s = Integer.toBinaryString(n);
String[] arr = s.split("0");
if(arr.length<1) {
return arr.length+1; //如果没有1就返回+1
}
int res=arr[0].length()+1; //暂定最终结果
for (int i = 1; i < arr.length; i++) { //从第二位开始
int temp=arr[i-1].length()+arr[i].length()+1; //获取当前值和上一位值+1 就相当于连起来试
res=Math.max(res,temp); //每次找最大的res
}
return res;
}

结果


LeetCode数组

1160.拼写单词(统计出现次数)

题目

分析

1. 主要思想就是:通过计算参考表和单词表每个单词出现次数对比(参照表出现次数一定要比找的多 才可能拼出来)
2. 具体步骤:
    2.1 分别设计一个jishu数组统计参考表每个单词出现次数 || 一个temp数组统计要查的每个单词的出现次数(用完就要清0)
    2.2 然后每个单词位都需要对比,然后对比成功+1之后达到26就说明能凑出来这个单词,输出长度。 

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class PingXieDanCi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
String[] words=new String[n]; //输入要判断的words表
for(int i=0;i<words.length;i++){
words[i]=input.next();
}
String chars=input.next(); //输入chars字符串
//可以试试每一次统计是否正确
/*int[] b=countCharacters(words,chars);
for(int i=0;i<26;i++){
if(b[i]!=0) {
System.out.println((char) (i + 97) + "有" + b[i] + "个");
}
}*/
System.out.println(countCharacters(words,chars));
}

public static int countCharacters(String[] words, String chars) {
int sum=0; //记录总长度
char[] a=chars.toCharArray(); //chars字符串转字符数组
int[] jishu=new int[26];
int[] temp=new int[26];

for(int i=0;i<chars.length();i++){
jishu[chars.charAt(i)-97]++; //计算chars字符串中各单词个数
}

for(int i=0;i<words.length;i++){
int chang=words[i].length(); //计算每一个要判断的词汇的长度

for(int j=0;j<words[i].length();j++){
temp[words[i].charAt(j)-97]++; //计算chars字符串中各单词个数
}

//对比两个数组
int flag=0; //每位判断是否满足条件
for(int z=0;z<26;z++){
if(jishu[z]>=temp[z]){
flag+=1; //满足要凑的比我有的少 就+1
}
if(jishu[z]<temp[z]){
break; //有参考表没有的单词 一定凑不出来!
}
}

if(flag==26){
sum+=chang; //每一位都满足 就可以拼凑出来
}

//用完之后将temp数组清0
for(int w=0;w<26;w++){
temp[w]=0; //计算chars字符串中各单词个数
}

}
return sum;
}

}

结果


88.合并两个有序整数数组(ArrayList集合)

题目

分析

1. 主要通过有序的ArrayList集合存放两个数组元素
2. 通过Collections.sort()方法进行排序然后返回

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class HeBinShuZu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int m=input.nextInt(); //数组1的长度
int n=input.nextInt(); //数组2的长度
int[] a=new int[m]; //定义数组1
int[] b=new int[n]; //定义数组2
for(int i=0;i<m;i++){
a[i]=input.nextInt(); //按序输入数组1的值
}
for(int j=0;j<n;j++){
b[j]=input.nextInt(); //按序输入数组2的值
}

System.out.println("调函数之后的list"+merge(a,m,b,n).toString()); //list集合转字符串
}

public static ArrayList<Integer> merge(int[] nums1, int m, int[] nums2, int n) {
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<m;i++){
list.add(nums1[i]);
}
System.out.println("第一次添加之后的list:"+list.toString());
System.out.println("第一次的长度"+list.size());
System.out.println("----------------------");
for(int j=0;j<n;j++){
list.add(nums2[j]);
}
System.out.println("第二次添加之后的list:"+list.toString());
System.out.println("第二次的长度"+list.size());
System.out.println("----------------------");
Collections.sort(list);
System.out.println("排序后的list:"+list.toString());
System.out.println("排序后的长度"+list.size());
System.out.println("----------------------");
return list;
}

}

结果


53. 0-n-1中缺失的数字(双指针二分查找)

题目

分析

1. 数组下标计数:新建数组然后利用数组下标记录每个数组出现次数,如果出现次数为0就是缺失的数字。
2. 双指针:使用二分法进行分左右两部分对比,只要是顺序不缺少的话肯定是下标和当前值一定一样。
    2.1 左边没缺   左指针挪到中间指针的右边
    2.2 左边缺失   右指针挪到中间指针的左边

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class QueShiShuZi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int m=input.nextInt(); //数组1的长度
int[] a=new int[m]; //定义数组1
for(int i=0;i<m;i++){
a[i]=input.nextInt(); //按序输入数组1的值
}
System.out.println("挨个遍历"+missingNumber(a));
System.out.println("双指针"+missingNumber2(a));
}

//挨个遍历存到计数数组中
public static int missingNumber(int[] a) {
int que=0;
int[] b=new int[a.length+1];
for(int i=0;i<a.length;i++){
b[a[i]]++;
}
for(int i=0;i<b.length;i++){
if(b[i]==0){
que=i; //下标计数的数组里面没出现肯定就是缺失了
}
}
return que;
}

//双指针二分法查询
public static int missingNumber2(int[] a) {
int que=0; //缺失的结果
int left=0; //左指针
int right=a.length-1; //右指针
while(left<=right){
int zhong=(left+right)/2; //中间指针
if(a[zhong]==zhong){
left=zhong+1; //左边的下标和数值没有断就肯定是相等 所以缺失的在右边 左指针放在中间指针右边
}
else{
right=zhong-1; //左边肯定缺失了 右指针放到中间指针的左边
}
}
return left; //最后一定是三个指向同一个位置
}

}

实现


118.杨辉三角形(动态递归)

题目

分析

1. 动态递归:遍历迭代之后进行增加
2. list集合:使用Arraylist集合

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class YangHuiSanJiao {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt(); //输入杨辉三角形的行数
long[][] b=yanghui(n); //接住调用方法的结果
System.out.println("动态递归解法:");
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
System.out.printf(b[i][j]+" ");
}
System.out.println();
}
}

//动态递归
public static long[][] yanghui(int n){
if(n==0){
return null; //0行就返回null
}
long[][] a=new long[n][n];
a[0][0]=1; //第一行第一列赋值1 方便后面的加
for(int i=1;i<n;i++){ //从第二行开始
for(int j=0;j<n;j++) {
if(j==0){
a[i][j]+=a[i-1][j]; //第一列的只能加上面的
}else{
a[i][j]=a[i-1][j]+a[i-1][j-1]; //上面的和上面的左边之和
}
}
}
return a;
}

}

实现


26.删除排序数组中的重复项(HashSet集合)

题目

分析

1. 不重复就需要使用set集合:我们使用HashSet集合
2. 循环将每个数组元素往set插入(刚好不能插入重复的)
3. 输出set.size()就是最后要的长度

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ShanChuChongFu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(removeDuplicates(a));
}

public static int removeDuplicates(int[] nums) {
HashSet<Integer> set=new HashSet<Integer>(); //建立hashset集合
for(int i=0;i<nums.length;i++){
set.add(nums[i]); //遍历添加元素
}
System.out.println(set.toString()); //输出set集合元素
return set.size(); //输出set集合的长度
}
}

结果


1051.高度检查器(桶排序)

题目

分析

1. 非递减就是说必须是递增/相等
2. 利用桶排序数组下标记录每个桶的数量,然后进行对比,一旦桶里面的数量和下标不相等那么就是要移动的点,所有计数器加一

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class GaoDuJianChaQi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(heightChecker(a)); //调用结果返回
}

//桶排序
public static int heightChecker(int[] heights) {
int count=0; //用于记录最少需要几次
//建立1,2,3,4,5...100一共101个桶
int[] arr=new int[101];
//遍历数组 -- 计算每个桶中有多少元素
for(int i:heights){
arr[i]++;
}

for(int i=1,j=0;i<arr.length;i++){
while(arr[i]-->0){ //一直到结束(桶用完)
if(heights[j++]!=i){
count++; //非递减就是说必须下标和当前桶数量相等
}
}
}
return count; //返回次数
}

}

实现


674.最长连续递增序列(动态递归)

题目

分析

1. 主要是一个ans和count两个计数(ans一直是当前位置最长的序列长度)
2. 每一次判断如果是递增就+1 如果不符合就直接为1 这样保证每次最长的给了ans
3. 最后输出的时候看ans大还是count大就输出(有可能count一直++最后一次的时候count比ans还大一个)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class ZuiChangXuLie {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(findLengthOfLCIS(a));
}

public static int findLengthOfLCIS(int[] nums) {
if(nums.length<=1){
return nums.length; //长度0/1就是1
}
int ans=1; //存当前的最大的长度
int count=1;
for(int i=0;i<nums.length-1;i++){ //因为i+1 所以i只能到最长-1
if(nums[i]<nums[i+1]){
count++; //递增+1
}else{
count=1; //断了就从1开始
}
ans=count>ans?count:ans; //返回最大的值
}
return ans;
}

}

实现


35.搜索插入位置(双指针二分法)

题目

分析

1. 找到:就是二分法直到某一次中间指针和要找的一样
2. 没找到:就和之前的找缺少的数字一样不断地二分法

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class SouSuoChaRuWeiZhi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
int m=input.nextInt();
System.out.println(searchInsert(a,m)); //调用方法返回结果
}

public static int searchInsert(int[] nums, int target) {
int left=0;
int right=nums.length-1;
while(left<=right){
int zhong=(left+right)/2;
if(nums[zhong]==target){ //如果找到了就返回
return zhong;
}else //如果找不到就找缺的位置(和之前的找缺少点一样)
if(nums[zhong]<target){ //在右边
left=zhong+1;
}else{ //在左边
right=zhong-1;
}
}
return left;
}

}

结果


1299.将每个元素替换成右侧最大元素(反序遍历)

题目

分析

1. 这个题反序遍历会很好做!!!
2. 思路:
    2.1 设置max存放右边最大的值(对比一次就更新一次)
    2.2 设置temp存当前的值(用于更新对比)
    2.3 存放最大值max给当前值 然后进行max更新

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class TiHuanYouCeZuiDa {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
int[] b=replaceElements(a); //新数组接结果
for(int i=0;i<n;i++){
System.out.print(b[i]+" ");
}
}
//反序遍历
public static int[] replaceElements(int[] arr) {
int max=-1; //一开始从最后一个开始赋-1
for(int i=arr.length-1;i>=0;i--){
int temp=arr[i];
arr[i]=max; //当前值赋给右边最大值
max=temp>max?temp:max; //max更新为右边最大值
}
return arr;
}

}

结果


167.两数之和II -输入有序数组(双指针)

题目

分析

1. 使用双指针思路: 左右指针相加计算
2. 计算思路(return new int[]{left+1,right+1}):
    2.1 左右指针之和 == target  就直接新建数组返回两个下标
    2.2 左右指针之和 < target 左边太小 左指针右移
    2.3 左右指针之和 > target 右边太大 右指针左移

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class LiangShuHe {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
int m=input.nextInt();
int[] c=twoSum(a,m); //接结果数组
for(int i=0;i<2;i++){
System.out.print(c[i]+" ");
}

}

public static int[] twoSum(int[] numbers, int target) {
if(numbers==null){
return null;
}
int left=0; //左指针
int right=numbers.length-1; //右指针
while(left<right){
int sum=numbers[left]+numbers[right]; //两个指针所在数组的值
if(sum==target){
return new int[]{left+1,right+1}; //直接返回一个新建数组 值就是两个下标
}else
if(sum<target){ //左边的太小 左指针右移
left++;
}
else{ //右边的太大 右指针左移
right--;
}
}
return null;
}

}

结果


1266.访问所有点的最小时间(切比雪夫距离)

题目

分析

其实就是dx和dy的最大值之和

代码

1
2
3
4
5
6
7
8
9
public int minTimeToVisitAllPoints(int[][] points) {
int res=0; //最后的距离
for(int i=1;i<points.length;++i){
int xMinus=Math.abs(points[i][0]-points[i-1][0]);
int yMinus=Math.abs(points[i][1]-points[i-1][1]);
res+=(xMinus>yMinus?xMinus:yMinus); //加两坐标差最大值
}
return res;
}

结果


1010.总持续时间可被60整除的歌曲(排列组合)

题目

分析

1. 思路:主要是卡在了如何配对 因为假如20和40配对了但是20还可以和后面的100配对所以没办法取消
        因此借鉴了大佬的将所有数组%60取余数进行分类讨论
2. 具体实现:
        2.1 余数是0的两两配对选择   n*(n-1)/2
        2.2 余数是30的两两配对也是  n*(n-1)/2
        2.3 其他余数就是 n*m

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class LiuShiZhengChuGeQu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(numPairsDivisibleBy60(a)); //调用方法返回结果
}

public static int numPairsDivisibleBy60(int[] time) {
int[] yu=new int[60];
for(int i=0;i<time.length;i++) {
yu[time[i]%60]++; //每个数字的余数放在yu数组对应下标
}
//记录总数的count
int count=0;
//1. 余数是0的情况两两选择 ls*(ls-1)/2
int ls=yu[0];
count=ls*(ls-1)/2;
//2. 余数是30的情况两两选择 ss*(ss-1)/2
int ss=yu[30];
count+=ss*(ss-1)/2;
//3.其余的1对59 2对58就用双指针进行移动添加 n*m
int i=1; //左指针
int j=59;//右指针
while(i<j){
count+=yu[i++]*yu[j--]; //1对59 2对58 3对57等等
}
return count; //返回成功的对数
}

}

结果


1351.统计有序矩阵中的负数

题目

分析

1. 类似于剑指offer内的统计正数的个数
2. 我们考虑用两个指针识别
    2.1 如果当前值>0 说明左边的这行都不符合 直接行指针下移一行
    2.2 如果当前值<0 说明下边的这列都符合   直接列指针左移一列 然后将这列的其他元素计数++

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class TongJiFuShu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int m=input.nextInt();
int n=input.nextInt();
int[][] a=new int[m][n];
for(int i=0;i<m;i++) {
for (int j=0;j<n;j++) {
a[i][j]=input.nextInt(); //输入二维数组
}
}
System.out.println("最终负数的个数是:"+countNegatives(a));
}

public static int countNegatives(int[][] grid) {
int count=0;
int hang=0; //初始从第一行
int lie=grid[0].length-1; //初始从最后一列开始
for(;hang<grid.length&&lie>=0;){
//1. 当前位置是正数 因为是递减所以它前面的不符合 直接换下一行
if(grid[hang][lie]>=0){
hang++; //换下一行
}
//2. 当前位置是负数 因为是递减所以它下面的都符合 直接换前面一列
else{
int temp=hang; //找个中间值替换行 不然while会改变hang影响count计数
while(temp<grid.length) {
System.out.print(grid[temp++][lie]+" "); //输出这列所有负数
}
count+=grid.length-hang; //这一列有几个数字符合 (行长度-当前行)
lie--; //换前一列
}
}
return count;
}

}

结果


1089.复写零(ArrayList集合)

题目

分析

这种题目主要是在0后面加0如果用数组比较麻烦,因此选择list集合

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class FuXieLin {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++) {
a[i]=input.nextInt();
}
ArrayList<Integer> lister=duplicateZeros(a);
for(int i=0;i<a.length;i++){
System.out.print(lister.get(i));
}

}

public static ArrayList<Integer> duplicateZeros(int[] arr) {
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<arr.length;i++){
if(arr[i]!=0){
list.add(arr[i]);
}
if (arr[i]==0) {
list.add(arr[i]);
list.add(arr[i]);
}
}
return list;
}

}

结果


605.种花问题(贪心)

题目

分析

1. 最左侧: 00...  考虑一侧是不是为0
2. 最右侧: ...00  考虑一侧是不是为0
3. 中间位置:...000...  考虑两侧是不是为0

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ZhongHua {public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++) {
a[i]=input.nextInt();
}
int m=input.nextInt();
System.out.println(canPlaceFlowers(a,m));
}

public static boolean canPlaceFlowers(int[] flowerbed, int n) {
if(n==0) {
return true; //不种花 返回成功
}
int count=0; //记录可以种的个数
int i=0; //记录下标
while (i < flowerbed.length) {
if (flowerbed[i] == 0 && (i == 0 || flowerbed[i - 1] == 0) && (i == flowerbed.length - 1 || flowerbed[i + 1] == 0)) {
flowerbed[i] = 1; //种花 +1
count++; //记录种了多少次
}
i++;
}
return count>=n; //返回是否可以
}

}

结果


1346.检查整数及其两倍数是否存在(哈希表HashMap)

题目

分析

1. 思路:使用hashMap进行存放数组的所有元素
2. 步骤:
    2.1 先新建hashmap将数组依次放入
    2.2 然后判断0的情况 如果有两个0以上就符合条件
    2.3 然后判断非0的情况 如果2倍的在map里面有的话就说明符合条件

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public boolean checkIfExist(int[] arr) {
Map map=new HashMap();
int zeroCount=0;// 对0进行特殊处理
for (int i = 0; i < arr.length; i++) {
if(arr[i]==0){// 计算0的个数
zeroCount++;
}
map.put(arr[i],0);
}
if(zeroCount>=2){// 如果存在两个以上的0,就符合
return true;
}else {
for (int i : arr) {
if (i!=0&&map.containsKey(i * 2)) { //如果map里面有2倍的i存在
return true;
}
}
}
return false;
}

结果


53.最大子序和(动态递归)

题目

分析

1. 首先对数组进行遍历,当前最大连续子序列和为 sum,结果为 ans
2. sum>0,则说明sum有增益效果,则sum保留并加上当前遍历数字
3. sum<=0则说明sum需要舍弃,则sum直接为当前遍历数字
4. 每次比较sum和ans的大小,将最大值置为ans,遍历结束返回结果

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ZuiDaZiXuHe {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++) {
a[i]=input.nextInt();
}
System.out.println(maxSubArray(a));
}

public static int maxSubArray(int[] nums) {
int ans=nums[0]; //当前最大就是第一个数
int sum=0;
for(int i=0;i<nums.length;i++){
if(sum>0){
sum+=nums[i]; //sum>0就说明对结果有好处
}else{
sum=nums[i]; //sum<0就说明需要扔掉 sum直接成为当前数字
}
ans=Math.max(ans,sum); //每次将当前最大值和 一轮之后的sum比较
}
return ans;
}

}

结果


643.子数组最大平均数(滑动窗口)

题目

分析

1. 思路:我们需要初始化前k个的值,设置ans存最好的结果,he是目前的结果。
2. 滑动窗口:he+=nums[i]-nums[i-k];  //加后面的一个就必须要减去前面一个

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ZuiDaPingJunShu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++) {
a[i]=input.nextInt();
}
int k=input.nextInt();
System.out.println(findMaxAverage(a,k)); //调用方法
}

public static double findMaxAverage(int[] nums, int k) {
double he=0;
for(int i=0;i<k;i++) {
he += nums[i]; //加上前面的k个当做初始和
}
double ans=he; //目前结果为初始和
for(int i=k;i<nums.length;i++){ //从前k个和之后遍历
he+=nums[i]-nums[i-k]; //加后面的一个就必须要减去前面一个
ans=Math.max(he,ans); //每次选最大的更新
}
return ans/k; //he/k就是最终平均值
}

}

结果


1122.循环遍历矩阵(四个指针)

题目

分析

1. 如果数组为空 --返回为null
2. 如果数组不为空
     2.1 建立ArrayList集合
     2.2 建立四个坐标用于标识数组变化
     2.3 从左往右(行:top            列:left到right)
     2.4 从上到下(行:top+1到bottom  列:right) 
     2.5 从右到左(行:bottom         列:right-1到left)  --注意可能最后是一行就不进行这一步
     2.6 从下到上(行:bottom-1到top  列:left)    --注意可能最后是一列就不进行这一步

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class XiangDuiPaiXu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int m=input.nextInt();
int[][] a=new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
a[i][j]=input.nextInt();
}
}
System.out.println(spiralOrder(a).toString()); //接结果按字符串返回
}

public static ArrayList<Integer> spiralOrder(int[][] a) {
if(a==null){
return null; //如果数组为空 就输出null
}
ArrayList<Integer> list=new ArrayList<Integer>(); //新建list集合存结果
int row=a.length; //行
int col=a[0].length; //列
int left=0; //二维数组上面行的最左边
int right=col-1; //二维数组上面行的最右边
int top=0; //二维数组左边的最上边
int bottom=row-1; //二维数组左边的最下边
/*
假设以4*4举例:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
*/
while(left<=right&&top<=bottom){
//1.左到右
for(int i=left;i<=right;i++){ //输出1 2 3 4(一直到right)
list.add(a[top][i]);
}
//2.上到下
for(int i=top+1;i<=bottom;i++){ //输出 8 12 16(从top+1到bottom)
list.add(a[i][right]);
}
//3.右到左
if(top!=bottom) {
for (int i = right-1; i >=left; i--) { //输出15 14 13(从right-1到left)
list.add(a[bottom][i]);
}
}
//4.下到上
if(left!=right) {
for (int i = bottom-1; i > top; i--) { //输出 9 5 1(从bottom到top-1)
list.add(a[i][left]);
}
}
//5.一轮结束之后更改四个坐标
left++;
right--;
top++;
bottom--;
}
return list; //返回集合
}

}

结果


53.在排列数组中查找出现次数(二分法)

题目

分析

1. 使用两次二分法确定左边和右边界限
2. 最终次数就是出现的长度 (right-right-1)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

public class ChaZhaoShuZi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
int m=input.nextInt();
System.out.println(search(a,m));
}

public static int search(int[] nums, int target) {
int left=0;
int right=nums.length-1;
//1. 找右边界
while(left<=right){
int middle=(left+right)/2;
if (nums[middle]<=target){ //一直找最右边的数字!!!!!!
left=middle+1; //在右边
}else{
right=middle-1; //在左边
}
}
int righter=left;

//初始化左右指针
left=0;
right=nums.length-1;

//2. 找左边界
while(left<=right){
int middle=(left+right)/2;
if (nums[middle]>=target){ //一直找最左边的数字!!!!!!!
right=middle-1; //在右边
}else{
left=middle+1; //在左边
}
}
int lefter=right;

return righter-lefter-1; //返回出现区间的大小
}

}

结果


面试4.二维数组中查找(两个指针移动)

题目

分析

1. 制定hang和lie两个指针
2. 二维数组遍历
    /*
        1 4 7 11 15
        2 5 8 12 19
        3 6 9 16 22      假设目标是13
        10 13 14 17 24
        18 21 23 26 30
    */
    2.1 只要当前的比target大(16>13) 说明这一列下面都不符合    换前一列lie--;
    2.2 只要当前的比target小(7<13)  说明这一行左边的都不符合  换下一行hang++;
    2.3 直到遇到的话输出true,没有的话就是false

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ErWeiShuZuChaZhao {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int m=input.nextInt();
int[][] a=new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
a[i][j]=input.nextInt();
}
}
int target=input.nextInt();
System.out.println(findNumberIn2DArray(a,target));
}

public static boolean findNumberIn2DArray(int[][] a, int target) {
int hang=0;
int lie=a.length-1;
for(int i=0;i<a.length;i++){ //二维数组循环
for(int j=0;j<a[i].length;j++){
if(a[i][j]>target){ //这列下面的都比当前的大 只能换前一列找
lie--;
}
if(a[i][j]<=target){ //这行没看的了 换下一行
hang++;
}
if(a[i][j]==target){ //找到了就返回true
return true;
}
}
}
return false;
}

}

结果


面试3.数组中重复的数字(数组下标存储)

题目

分析

1. 遍历数组使用Arrays.sort()方法排序之后通过数组下标存到另外一个数组B。
2. 遍历数组如果里面的值>1就直接break就行,题目只需要输出一个。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ShuZuChongFuShu {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(findRepeatNumber(a));
}

public static int findRepeatNumber(int[] nums){
int flag=0;
Arrays.sort(nums);
int[] b=new int[nums.length];
for(int i=0;i<nums.length;i++){
b[nums[i]]++;
}
for(int i=0;i<nums.length;i++){
if(b[i]>1){
flag=i;
break;
}
}
return flag;
}

}

结果


面试17.主要元素(投票)

题目

分析

1. 思路:我们可以sort排序之后查看中间位置的数字就是主要元素。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ZhuYaoYuanSu {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(majorityElement(a));
}

public static int majorityElement(int[] nums) {
if (nums == null || nums.length == 0) {
return -1; //如果没有数组/数组为空 --> 返回-1
}
Arrays.sort(nums); //排序
int result = nums[nums.length/2]; //下标在中间的数一定是要找的数
return result;
}
}

结果


面试17.22.单词转换(DFS/BFS)

题目

分析

代码

1
2


结果


面试17.4消失的数字(双指针二分法)

题目

分析

找缺失数字系列题目
1. 排序(保证按照顺序啦)
2. while循环双指针二分法
    2.1 中间数==下标(前面的没缺少) 左指针到中间的右边一个数字
    2.2 中间数!=下标(前面有缺少)     右指针到中间的左边一个数字

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class DanCiZhuanHuan {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(missingNumber(a));
}

public static int missingNumber(int[] nums) {
Arrays.sort(nums); //排序
int left=0; //左指针
int right=nums.length-1; //右指针
while (left <= right) {
int zhong = (left + right) / 2;
if(nums[zhong]==zhong){
left=zhong+1; //左边的下标和数值没有断就肯定是相等 所以缺失的在右边 左指针放在中间指针右边
}
else{
right=zhong-1; //左边肯定缺失了 右指针放到中间指针的左边
}
}
return left;
}

}

结果


面试16.17.连续数列(动态递归)

题目

分析

1. 首先对数组进行遍历,当前最大连续子序列和为 sum,结果为 ans
2. sum>0,则说明sum有增益效果,则sum保留并加上当前遍历数字
3. sum<=0则说明sum需要舍弃,则sum直接为当前遍历数字
4. 每次比较sum和ans的大小,将最大值置为ans,遍历结束返回结果

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class LianXuShuLie {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(maxSubArray(a));
}

public static int maxSubArray(int[] nums) {
int ans=nums[0]; //当前最大就是第一个数
int sum=0;
for(int i=0;i<nums.length;i++){
if(sum>0){
sum+=nums[i]; //sum>0就说明对结果有好处
}else{
sum=nums[i]; //sum<0就说明需要扔掉 sum直接成为当前数字
}
ans=Math.max(ans,sum); //每次将当前最大值和 一轮之后的sum比较
}
return ans;
}

}

结果


面试16.15珠玑妙算(HashMap集合)

题目

分析

1. 伪猜中=real-fake
2. 使用HashMap集合:一个存储字母一个是次数
3. 遍历solution字符串,保存每个字母对应的次数
4. 遍历guess字符串,两个字符串 抵消掉猜对的数字其他的就是伪猜中的次数(计算最大匹配成功数)
5. 遍历两个字符串得到真正匹配成功数
6. 最后新建数组弹出real和real-fake即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class ZhuJi {
public static void main(String[] args){
Scanner input=new Scanner(System.in);
String a=input.next();
String b=input.next();
int[] ans=masterMind(a,b);
for(int i=0;i<ans.length;i++){
System.out.print(ans[i]+" ");
}
}

public static int[] masterMind(String solution, String guess) {
HashMap<Character,Integer> map = new HashMap<Character,Integer>();

for(char c:solution.toCharArray()){
map.put(c,map.getOrDefault(c,0)+1); //往map里面存solution里面每个字母的个数
}

int fake=0,real=0; //fake伪没猜中 //real为猜中

for(char c:guess.toCharArray()){
if(map.containsKey(c)&&map.get(c)>0){ //抵消掉猜对的数字其他的就是伪猜中的次数
fake++;
map.put(c,map.get(c)-1); //减少出现的次数(最后计算最大的匹配成功数)
}
}

for(int i=0;i<4;i++){
if(solution.charAt(i)==guess.charAt(i)){real++;} //如果每一位相等说明猜中了+1
}

int[] ans={real,fake-real}; //伪猜中包含猜中次数
return ans;
}

}

结果


面试08.03魔术索引(双指针二分法)

题目

分析

1. 和找缺失的数组的下标题一样
2. 双指针二分法判断

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MoShuSuoYin {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(findMagicIndex(a));
}

public static int findMagicIndex(int[] nums) {
int left = 0, right = nums.length; //左右指针
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] != mid) //左边有缺少的数字
{
if (nums[mid] >= 0)
{
right = mid;
}
else
{
left = mid + 1; //在右边
}
}
else
{
left = mid + 1; //右边有缺少的数字
}
}
return left -1;
}

}

结果


面试01.02判断是否互为字符重排

题目

分析

1. 统计每个出现次数如果出现次数一样就肯定可以重排
2. 步骤
    2.1 如果长度不同肯定false
    2.2 将s1的每个单词的ascii码存进去一个int数组
    2.3 将s2的每个单词的ascii码从int数组删除掉
    2.4 如果数组还是一直全是0就成功true

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class ZiFuChongPai {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s1=input.next();
String s2=input.next();
System.out.println(CheckPermutation(s1,s2));
}

public static boolean CheckPermutation(String s1, String s2) {
int l1=s1.length();
int l2=s2.length();
if(l1!=l2){ //如果两个长度不一样直接返回false
return false;
}
int[] index=new int[128]; //char存的是里面的ascii码
for(int i=0;i<l1;i++){
index[s1.charAt(i)]++; //将s1里面的字符的ascii码添加到数组
index[s2.charAt(i)]--; //将s2里面的字符的ascii码从数组删除
}
for(int i=0;i<index.length;i++){
if(index[i]!=0){ //如果存的那个数组里面全空 那就是能重排
return false;
}
}
return true;
}

}

结果


面试01.01判断字符是否唯一(首次和最后一次出现位置不同)

题目

分析

1. 使用indexof和lastindexof方法
2. 只要首次和末次出现位置不同就说明至少出现两次以上!!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class PanDuanWeiYi {  public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s1=input.next();
System.out.println(isUnique(s1));
}
public static boolean isUnique(String s1) {
for(char ch:s1.toCharArray()){ ///增强for循环 s1的每个字符
//第一次和最后一次出现位置不同(一定至少两个)
if(s1.indexOf(ch)!=s1.lastIndexOf(ch)){
return false;
}
}
return true;
}

}

结果


面试01.07旋转矩阵(二次旋转)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void rotate(int[][] matrix) {
int n=matrix.length; //获取数组长度
//1. 以对角线(左上-右下)为轴反转
for(int i=0;i<n-1;i++){ //假如n=3 只取0 1这两行(我们只看右上角)
for(int j=i+1;j<n;j++){ //假如n=3 依次取01 02 12(右上角三个数字)
int tmp=matrix[i][j];
matrix[i][j] = matrix[j][i]; //对角线的两边的两个数互换
matrix[j][i] = tmp;
}
}

//2. 每一行以中点进行翻转
int mid=n>>1; //就是取一半(>>二进制向右挪一位)
/*
3(0011) -> 1(0001) 所以三列中间的是第二列(下标是1)
5(0101) -> 2(0010) 所以五列中间的是第三列(下标为2)
*/
for (int i = 0; i < n; i++) { //所有行都循环
for (int j = 0; j < mid; j++) { //列只找到左边一半
int tmp = matrix[i][j];
matrix[i][j] = matrix[i][n - 1 - j]; //中点行两边的互换
matrix[i][n - 1 - j] = tmp;
}
}

}

结果


面试01.08零矩阵(一维数组定行列)

题目

分析

1. 思路:
    1.1 新建两个一维数组存放需要清0的行和列 
2. 步骤:
    2.1 先遍历获取出来要清0的行和列的下标
    2.2 然后遍历查找需要清0的行然后清0
    2.3 然后遍历查找需要清0的列然后清0

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class LingJuZheng {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int m = input.nextInt();
int n = input.nextInt();
int[][] a = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++){
a[i][j] = input.nextInt();
}
}
setZeroes(a); //调用方法进行清0
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++){
System.out.print(a[i][j]+" "); //输出数组
}
System.out.println();
}

}

public static void setZeroes(int[][] matrix) {
boolean[] line = new boolean[matrix.length]; //设置两个存放行和列的布尔数组
boolean[] column = new boolean[matrix[0].length];
//1.找出要清零的行列
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 0) {
line[i] = true; //存放要清0的行
column[j] = true; //存放要清0的列
}
}
}

//2.开始对行清零
for (int i = 0; i < matrix.length; i++) {
if (line[i]) { //行存在
for (int j = 0; j < matrix[0].length; j++) {
matrix[i][j] = 0; //所在列清0
}
}
}

//3.开始对列清零
for (int i = 0; i < matrix[0].length; i++) {
if (column[i]) { //列存在
for (int j = 0; j < matrix.length; j++) {
matrix[j][i] = 0; //所在行清0
}
}
}

}

}

结果


面试05.08绘制直线(位运算)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution {
public int[] drawLine(int length, int w, int x1, int x2, int y) {
int[] ans=new int[length];
int low=(y*w+x1)/32;
int high=(y*w+x2)/32;
for(int i=low;i<=high;i++){
ans[i]=-1;
}
ans[low]=ans[low]>>>x1%32;
ans[high]=ans[high]&Integer.MIN_VALUE>> x2 % 32;
return ans;

}
}

结果


面试08.04幂集(回溯法)

题目

分析

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MiDeng {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int[] a=new int[n];
for(int i=0;i<n;i++){
a[i]=input.nextInt();
}
System.out.println(subsets(a));
}

public static List<List<Integer>> subsets(int[] nums) {
//结果集合
List<List<Integer>> list = new ArrayList();
//回溯方法
backtrack(list,new ArrayList<>(),nums,0);
//返回list集合
return list;
}

public static void backtrack(List<List<Integer>>list,List<Integer>tempList,int []nums,int start){
List<Integer> templist=new ArrayList<>(); //里面临时集合templist
list.add(tempList); //新建名为tempList集合
for(int i=start;i<nums.length;i++){
tempList.add(nums[i]); //把start之后的元素添加进去
backtrack(list,tempList,nums,i+1); //进行下次回溯
tempList.remove(tempList.size()-1); //移除最后一个
}
}

}

结果


所有奇数长度子数组的和

题目

分析

1. 难点就在于怎么确定截取的位置,怎么找到所有奇数位置
2. 考虑从第一位开始找每一位符合的奇数,所以i从0到len
3. 然后就是考虑j的变化,因为每次i变化之后j只能从i后面取,所以j从等于i开始遍历
4. 符合条件: 如果j-i是0 2 4这种的话就是符合条件(i和j都是第二位的话,就算是奇数位,所以是0 2 4)
5. 就可以单独写一个方法计算i到j的和,每次if符合调用返回结果。    

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[] arr=new int[]{1,4,2,5,3};
System.out.println(sumOddLengthSubarrays(arr));
}

public static int sumOddLengthSubarrays(int[] arr) {
int res=0;
int len=arr.length; //获取数组长度
for(int i=0;i<len;i++){
for(int j=i;j<len;j++){
if((j-i)%2==0){ //奇数距离
res+=find(i,j,arr);
System.out.println("这次是从第"+(i+1)+"到第"+(j+1)+"个位置求和,和为:"+res);
}
}
}
return res;
}

public static int find(int i,int j,int[] arr){
int sum=0;
for(int z=i;z<=j;z++){
sum+=arr[z];
}
return sum;
}

}

结果


根据数字二进制下1的数目排序(Integer.bitCount()方法)

题目

分析

1. 遍历所有数组求1的个数
2. 将每个数中1的个数*10000+原数
3. Arrays.sort()排序之后在%10000就可以得到排序

代码

1
2
3
4
5
6
7
8
9
10
11
12

public int[] sortByBits(int[] arr) {
int[] map = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
map[i] = Integer.bitCount(arr[i]) * 10000000 + arr[i]; //1的个数*100000000+原数
}
Arrays.sort(map); //排序
for (int i = 0; i < map.length; i++) {
map[i] = map[i] % 10000000; //取余
}
return map; //返回数组
}

结果


分糖果(一半和不同糖果数对比)

题目

分析

1. 妹妹和弟弟手里都是a.length/2个糖果
2. 具体妹妹拿多少就要看set去重和平均值得大小对比

代码

1
2
3
4
5
6
7
8

public int distributeCandies(int[] candies) {
HashSet < Integer > set = new HashSet < > ();
for (int candy: candies) {
set.add(candy); //记录不同糖果的个数
}
return Math.min(set.size(), candies.length / 2); //对比两者
}

结果


数组序号转换(map集合存<数字,序号>)

题目

分析

1. 因为有重复的数字 所以直接输出不太好弄
2. 使用map集合存储每个数字和数字出现的位置(排序sort之后就好弄)
3. for循环a数组,这样可以顺序填进去

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

public static int[] arrayRankTransform(int[] a) {
int n=a.length; //数组长度
int[] temp=a.clone(); //赋值a数组生成新的temp数组
Arrays.sort(temp); //sort排序
int count=1;
Map<Integer,Integer> map=new HashMap<>(); //生成map集合
for(int i=0;i<n;i++){
if(!map.containsKey(temp[i])){
map.put(temp[i],count++); //只将不重复的数字 存入数字和序号
}
}
for(int i=0;i<n;i++){
a[i]=map.get(a[i]); //遍历a数组 将序号放入
}
return a; //输出原数组
}

结果


最长和谐子序列(枚举)

题目

分析

1. 从第一位开始遍历 找到跟他一样大而且比他大1的数字就count计数器+1
2. 注意就是一定要有比他大1的数,用一个布尔值确定有没有。!!!!!

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public int findLHS(int[] nums) {
int res = 0; //接住最后结果
for (int i = 0; i < nums.length; i++) { //遍历所有元素
int count = 0; //记录每个元素的个数
boolean flag = false;
for (int j = 0; j < nums.length; j++) {
if (nums[j] == nums[i]) //找到和当前值一样的值可以当做序列值
count++;
else if (nums[j] + 1 == nums[i]) { //找到比当前值大1的值也可以当序列值
count++;
flag = true; //标志改为true 说明满足有最大最小值
}
}
if (flag)
res = Math.max(count, res); //如果有的话 就找最大值
}
return res; //返回res结果
}

结果


剑指offer

数组

二维数组的查找

面试三题目

题目分析

1. 使用暴力二重循环遍历
2. 使用题目中横竖都递增的原理:
    2.1 如果相等输出true
    2.2 目标n>a[i][j] 说明我们要找的比现在位置的要大 (这一行都比目标的小)所以下移一行 i++
    2.3 目标n<a[i][j] 说明我们要找的比现在位置的要小 (这一列都比目标的大)所以左移一列 j--

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class erweishuzuchazhao {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
System.out.println("输入要查找的元素的值:");
2020/5/18 10:14:36 System.out.println("输入二维数组的行:");
int h=input.nextInt(); //输入二维数组的行
System.out.println("输入二维数组的列:");
int l=input.nextInt(); //输入二维数组的列
int[][] a =new int[h][l];
System.out.println("输入二维数组内容:");
//输入二维数组的值
for(int i=0;i<h;i++){
for(int j=0;j<l;j++){
a[i][j]=input.nextInt();
}
}
//调用函数得到结果
if(chazhao(a,n)==1){
System.out.println("要查询的"+n+"存在");
}else{
System.out.println("要查询的值不存在");
}
}

//1. 二维数组循环遍历(不推荐)
public static int chazhao(int[][] a,int n){
int f=0;
for(int i=0;i<a.length;i++){
for(int j=0;j<a[i].length;j++){
if(a[i][j]==n)
{
f=1; //存在就赋值为11
}
}
}
return f;
}

//2. 布尔值判断
public boolean Find(int n, int [][] a) {
//判断数组空
if((a==null||a.length==0)||(a.length==1&&a[0].length==0)){
return false;
}
int i=0; //左上角
int j=a[0].length-1; //右上角
while(i<=a[0].length-1&&j>=0){
if(n==a[i][j]) {return true;} //找到了
if(n<a[i][j]) {j--;} //这一列都比n大 (往左移动)
else{ i++;} //这一行都比n小(往下移动)
}
return false;
}

}

实现结果


字符串

替换空格

面试四题目

请实现一个函数,把字符串中的每个空格替换成”%20”.例如输入“We are happy.”,则输出为”We%20are%20happy.”

题目分析

1. 这类题解决网络编程中由于URL参数中含有特殊字符导致服务器端无法获取正确的参数值。
    1.1 解决规则:通过在'%'后跟上ASCII码的两位十六进制的表示。
    1.2 解决举例:空格的ASCII码是32(16进制的0x20),因此空格被替换为"%20"
2. 空格替换的实现方式:
    2.1 将原来的字符串中的空格字符 --> '%' '2' '0' 这三个字符(覆盖修改字符串后面的内存)
    2.2 新建StringBuilder字符串在此上面替换(可以自己分配足够多的内存) 
    2.3 新建数组实现

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class zifutihuan {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.nextLine();
System.out.println(replaceSpace(s));
System.out.println(replaceSpace(s));
}

//1.新建数组实现
public static char[] replaceSpace(String s){
if(s==null){
return null; //字符串为空就输出null
}
char[] a=new char[s.length()*3];
int size=0;
//循环新字符数组然后进行更替操作
for(int i=0;i<s.length();i++){
char c=s.charAt(i); //获取s字符串的对应字符
if(c==' '){
a[size++]='%';
a[size++]='2';
a[size++]='0';
}else{
a[size++]=c; //把原来的字符放进去
}
}

return a;
}

//2.新建StringBuilder类实现
public String replaceSpace(StringBuffer str) {
if(str==null){
return null; //字符串为空就输出null
}
StringBuilder s=new StringBuilder();
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
if(c==' '){
s.append('%');
s.append('2');
s.append('0');
}else{
s.append(c);
}
}
return s.toString();
}

}

实现结果

字符串的排列

面试题二十八题目

题目分析

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ZiFuPaiLie {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.nextLine();
System.out.println("要排列的字符串:"+s);
System.out.println("排列之后的结果"+Permutation(s));
}

public static ArrayList<String> Permutation(String str) {
ArrayList<String> ans=new ArrayList<String>();
char[] a=str.toCharArray(); //字符串转数组

return ans;
}

}

实现结果


链表

从尾到头打印链表

面试五题目

输入一个链表的头结点,从尾到头反过来打印每个结点的值。

题目分析

1. 很明显这需要用栈实现,将链表的每个元素压入栈然后弹出

代码实现

ListNode类:

1
2
3
4
5
6
7
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val=x;
}
}

mianshisan类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class mianshisan {
public static void main(String[] args) {
ListNode head1=new ListNode(1);
ListNode head2=new ListNode(3);
ListNode head3=new ListNode(2);
head1.next=head2; //生成链表:1 --> 2 --> 3
head2.next=head3;
head3.next=null;
//调用方法
reversePrint(head1);
}

//自定义反转打印的方法
public static void reversePrint(ListNode head){
//压栈
Stack<ListNode> stk=new Stack<>();
ListNode temp=head;
while(temp!=null){ //直到指向最后一个位置
stk.push(temp);
temp=temp.next; //不断更替
}
//循环输出
while(!stk.isEmpty()){
System.out.println(stk.pop().val); // 挨个出栈
}
}

}

实现结果


重建二叉树

面试六题目

题目分析

此题就是

代码实现

1
2


实现结果


递归和循环

斐波那契数列

面试九题目

题目分析

1.递归:
    1.1 如果n=1/n=0就返回n
    1.2 其他情况下递归调用n-1和n-2

2.动态规划:    
    不断循环递进求最后一个数的原理
     c=a+b;  //第三个数
     a=b;   //原来的b成为下一轮的a
     b=c;   //原来的c成为下一轮的b

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class FeiBo {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
//System.out.println("递归:"+digui(n)); //递归
System.out.println("动态规划:"+dongtai(n)); //动态代理
}

//递归
public static int digui(int n){
if(n<=0){
return 0;
}
if(n==1){
return 1;
}
return digui(n-1)+digui(n-2); //从第二项开始依次递增
}

//动态规划
public static long dongtai(int n){
if(n<=0){
return 0;
}
if(n<=2){
return 1;
}
long a=1;
long b=1;
long c=2;
for(int i=2;i<n;i++){ //依次往后挪动
c=a+b; //第三个数
a=b; //原来的b成为下一轮的a
b=c; //原来的c成为下一轮的b
}
return c;
}

}

实现结果

1.测试小数字时候递归还可以:

2.测试大的数字之后递归暴露了自己的缺点:

青蛙跳台阶(普通)

面试九题目

题目分析

1.递归
    1.1 前三项和n一样
    1.2 第四项之后开始就是前两项之和(斐波那契数列)
2.动态规划
    不断循环递进求最后一个数的原理
     c=a+b;  //第三个数
     a=b;   //原来的b成为下一轮的a
     b=c;   //原来的c成为下一轮的b

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.Scanner;
public class FeiBo {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println("递归:"+digui(n)); //递归
System.out.println("动态规划:"+dongtai(n)); //动态代理
}

//递归
public static int digui(int n){
if(n<=3){
return n; //前三个就是 1 2 3 (5 8...)
}
return digui(n-1)+digui(n-2); //其余就是前两者之和
}

//动态规划
public static long dongtai(int n) {
if(n<=3){
return n; //前三个就是 1 2 3 (5 8...)
}
long sum=0;
long a=1;
long b=2;
for(int i=2;i<n;i++){
sum=a+b; //后面的是前面的两次
a=b; //现在的第二个是下一轮的第一个
b=sum; //现在的总和是下一轮的第二个
}
return sum;
}

}

实现结果

青蛙跳台阶(变态)

面试九题目

题目分析

 1.推理可得到f(n)=2f(n-1)

f(1) = 1;
f(2) = f(1)+1 = f(1)+f(1) = 2*f(1) = 2;
f(3) = f(2)+f(1)+1 = f(2)+f(1)+f(1)= f(2)+2*f(1) = f(2)+f(2)=2*f(2) = 2*2;
f(k) = f(k-1) + f(k-2) + …+ f(2)+ f(1) + 1= f(k-1) + f(k-2) + …+ f(3)+f(2)+f(1) + f(1)
     = 2*f(k-1)

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class QingWa {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println("递归:"+tiao(n)); //递归
System.out.println("动态规划:"+tiaoer(n)); //动态规划
}

//递归实现
public static int tiao(int n) {
if(n<=1){
return 1; // f(n)=1
}
return 2*tiao(n-1); // f(n)=2*f(n-1)
}

//动态规划
public static int tiaoer(int n) {
if(n<=0){
return 0; // f(0)=0
}
if(n==1){
return 1; // f(1)=1
}
int a=1;
int b=1;
for(int i=1;i<n;i++){
b=a*2; //当前的值是上一个的二倍
a=b; //计算出来的值当做下一轮的数
}
return b;
}

}

实现结果


位运算

二进制中1的个数

面试十题目

题目分析

1.关于求解1的个数(负数容易死循环--它要整体n/2右移保证还是一个负数所以前面一直补1--不可能将n/2为0)
    1.1 循环(只解决正数):从个位不断取出来n(n%10)的数字判断是否为1然后n/n缩小范围最后输出个数
    1.2 位运算(n与n-1):会把最右边的1变为0 能进行多少次就相当于有多少个1
    1.3 使用Integer.toBinaryString(n)将n的二进制转为字符串,遍历1的个数

2.关于输出每位数字
    2.1 字符串拼接:(字符串+数字=数字拼一起)
    2.2 数组存放:(每一位放数组内反序输出)

代码实现(只能处理正数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class QiuYi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
System.out.println("一共有:"+qiu(n)); //1的个数
System.out.println(qiuer(n)); //每一位的值
}

//求出有多少个1
private static long qiu(int n) {
long sum=0; //计数器
int m=1; //每一位的值
while(n!=0){
m=n%2;
if(m==1){
sum++; //如果是1就计数器加1
}
n=n/2;
}
return sum;
}

//输出每一位的值
private static String qiuer(int n) {
int[] a=new int[100]; //定义数组存放每一位元素
String target="";
int i=0; //获取每一位的数字
while(n!=0){
i=n%2;
target=i+target; //字符串+数字=数字附加(将每次i放前面加 因为从个位取出来是反序的)
n=n/2;
}
return target;
}

}

代码实现(位运算)

1100为例,减去1就是1011,两者相与就是1000(相当于第二位的1没了)

1
2
3
4
5
6
7
8
private static int qiusan(int n) {
int sum=0;
while(n!=0){
n=n&(n-1); // (原整数-1)与(原整数) == (最右边1变为0)
sum++; //变一次就相当于记录一个1变化
}
return sum;
}

代码实现(Integer.toBinaryString()然后遍历)

1
2
3
4
5
6
7
8
9
10
11
12
//Integer.toBinaryString()
private static int qiusi(int n) {
int sum=0;
String s=Integer.toBinaryString(n); //n的二进制转为字符串
for(int i=0;i<s.length();i++){
char c=s.charAt(i); //取出每一个位置的字符
if(c=='1'){
sum++; //字符如果为1计数器就加一
}
}
return sum;
}

实现结果

普通算法(只能解决正数 负数不能/2)

位运算(正负数均可)


易错面试题

数值的整数次方

面试十一题目

题目分析

1. 底为0   指数无论  --> 0
2. 底不为0 指数为0   --> 1
3. 底不为0 指数小于0 --> 按照循环求解之后答案取倒数
4. 底不为0 指数大于等于1 --> 正常流程

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class CIFang {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
double n=input.nextDouble();
int m=input.nextInt();
System.out.println(n+"的"+m+"次方是"+cifang(n,m));
}

public static double cifang(double base,int exponent){
double c=1;
//底为0
if(base==0){
return 0;
}
if(exponent==0){ //任何数的0次方都是1
return 1;
}
//底不为0 指数是负数
if(exponent<0){
exponent=-exponent;
while (exponent--!=0) { //有多少m就乘多少次n
c*=base; //c=c*n 在前面的基础上乘n
}
c=1.0/c; //取倒数
}
//底不为o 指数大于等于1
if(exponent>=1) {
while (exponent--!=0) { //有多少m就乘多少次n
c*=base; //c=c*n 在前面的基础上乘n
}
}
return c;
}

}

实现结果

打印1到最大的n位数

面试十二题目

题目分析

1. 暴力法(无法解决大数问题):先算出最大值,然后按序输出
2. 数组/字符串:
3. 全排列:

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//1.暴力法(找到最大数然后按序输出)
public static String printNumbers(int n){ //传入一个n
int max=0; //输出的最大的值
//1.先求出最大数(方便定义数组下标大小)
for(int i=0;i<n;i++){
max=max*10+9; //从9 99 999 9999...
}
//2.通过最大值创建数组
int[] a=new int[max];
for(int i=1;i<=max;i++){
a[i]=i;
}
return Arrays.toString(a); //使用Arrays的方法将数组转为字符串
}

实现结果

数组中只出现一次的数字

题目

题目分析

1. 使用数组下标的好处:新建数组记录下标计数
2. 使用set集合(不能重复):然后将1次以上的直接弹出,其他的添加到set集合

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class YiCi {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<a.length;i++){
a[i]=input.nextInt(); //输入要判断的数组元素
}
System.out.println(Find(a));
}

public static Set<Integer> Find(int[] a) {
Set<Integer> s1=new HashSet<>();
for(int i=0;i<a.length;i++){
if(!s1.add(a[i])){ //如果重复了(2次以上)
s1.remove(a[i]); //移除set集合 里面剩下的就都是只出现一次的值
}
}
return s1;
}

}

实现结果

调整数组顺序(奇数在偶数前面)

面试十四题目

题目分析

思路:使用两个指针交换奇偶数(快排的感觉)
    1. 左右指针赋初始值
    2. 分下面三种情况
        2.1 左指针不超过右指针 + 左边值是奇数(不需要交换) --> 左指针右移
        2.2 左指针不超过右指针 + 右边值是偶数(不需要交换) --> 右指针左移
        2.3 其他情况下直接交换左右指针对应数组的值

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ShunXu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt(); //输入二维数组的行和列
int m=input.nextInt();
int[][] a=new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
a[i][j]=input.nextInt(); //输入要判断的数组元素
}
}


}

public static ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list=new ArrayList<Integer>(); //定义arraylist集合 底层是数组
int row=matrix.length; //行
int col=matrix[0].length; //列
int left=0;
int right=col-1;
int top=0;
int bottom=row-1;
return list;
}

}

实现结果

顺时针打印矩阵

面试二十题目

题目分析

1. 如果数组为空 --返回为null
2. 如果数组不为空
     2.1 建立ArrayList集合
     2.2 建立四个坐标用于标识数组变化
     2.3 从左往右(行:top    列:left到right)
     2.4 从上到下(行:top+1到bottom  列:right) 
     2.5 从右到左(行:bottom  列:right-1到left)  --但要注意可能最后是一行就不需要进行这一步
     2.6 从下到上(行:bottom-1到top  列:left)    --但要注意可能最后是一列就不需要进行这一步

关于left/right/bottom/top的分析:

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class ShunXu {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt(); //输入二维数组的行和列
int m=input.nextInt();
int[][] a=new int[n][m];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
a[i][j]=input.nextInt(); //输入要判断的数组元素
}
}

System.out.println(printMatrix(a)); //打印调用方法结果
}

public static ArrayList<Integer> printMatrix(int [][] matrix) {
if(matrix==null){
return null; //如果数组为空 就输出null
}
ArrayList<Integer> list=new ArrayList<Integer>(); //定义arraylist集合 底层是数组
int row=matrix.length; //行
int col=matrix[0].length; //列
int left=0; //二维数组上面行的最左边
int right=col-1; //二维数组上面行的最右边
int top=0; //二维数组左边的最上边
int bottom=row-1; //二维数组左边的最下边
while(left<=right&&top<=bottom){
//从左到右
for(int i=left;i<=right;i++){
list.add(matrix[top][i]);
}
//从上到下(从下一行开始向下走)
for(int i=top+1;i<=bottom;i++){
list.add(matrix[i][right]);
}
//从右到左(从左边一列开始向左走)
if(top!=bottom) { //如果是一行的话就不需要返回去(已经左到右)
for (int i = right - 1; i >= left; i--) {
list.add(matrix[bottom][i]);
}
}
//从下到上(从上一行开始向上走)
if(left!=right) { //如果是一列的话就不需要返回去(已经上到下)
for (int i = bottom - 1; i > top; i--) {
list.add(matrix[i][left]);
}
}
//下一个正方形矩阵(往里缩小 -- 变换四个下标)
top++;
right--;
left++;
bottom--;
}
return list;
}

}

实现结果


图的概念:

https://www.cnblogs.com/songgj/p/9107797.html

图的展示方式

1. 邻接表
2. 邻接矩阵(相通为1,不通为0)

邻接矩阵实现

Graph类(和顶点数组有关)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//顶点数组
public class Graph {
private Vertex[] vertex; //存放顶点的矩阵
private int currentSize; //下标
int[][] adjMat; //二维矩阵存放顶点之间的关系


public Graph(int size){
vertex=new Vertex[size]; //设置顶点数组大小
adjMat=new int[size][size]; //二维数组默认为0
}

//向图中添加顶点
public void addVertex(Vertex v){
vertex[currentSize++]=v;
}

//向图中添加边
public void addEdge(String v1,String v2){
int index1=0;
int index2=0;
for(int i=0;i<vertex.length;i++){
if(vertex[i].getValue().equals(v1)){ //如果要添加的和v1是相等的 就把下标给index1
index1=i;
break;
}
}
for(int i=0;i<vertex.length;i++){
if (vertex[i].getValue().equals(v2)) { //如果要添加的和v2是相等的 就把下表给index2
index2=i;
break;
}
}
//相通给1
adjMat[index1][index2]=1; //把对应的位置变1
adjMat[index2][index1]=1;

}

}

Vertex类(顶点类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//顶点类
public class Vertex {
private String value;

public Vertex(String value) {
super();
this.value = value;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

@Override
public String toString() {
return value;
}

}

TestGraph类(测试类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class TestGraph {
public static void main(String[] args) {
//创建五个顶点
Vertex v1=new Vertex("A");
Vertex v2=new Vertex("B");
Vertex v3=new Vertex("C");
Vertex v4=new Vertex("D");
Vertex v5=new Vertex("E");
Graph g=new Graph(5);
//增加节点
g.addVertex(v1);
g.addVertex(v2);
g.addVertex(v3);
g.addVertex(v4);
g.addVertex(v5);
//增加边
g.addEdge("A","C");
g.addEdge("B","C");
g.addEdge("A","B");
g.addEdge("B","D");
g.addEdge("B","E");
//打印二维矩阵
for(int[] a:g.adjMat){
System.out.println(Arrays.toString(a));
}

}
}

结果分析

结果展示


图的遍历

1. 深度优先搜索算法(用栈的方式思考)
2. 广度优先搜索算法(用队列的方式思考)

两种遍历讲解

举例图:

深度优先搜索算法(DFS)

走迷宫一样,当前顶点走到死路就返回一步看能不能再走,把死路位置的顶点弹出去

1. 栈先放入A顶点 (栈内:A)
2. 搜索邻接矩阵中第一行A顶点可以到达哪个顶点
3. 栈再放入B顶点 (栈内:B A)
4. 搜索邻接矩阵中第二行B顶点可以到达哪个顶点
5. 栈再放入C顶点 (栈内:C B A)
6. 搜索邻接矩阵中第三行C顶点可以到达哪个顶点
7. 没有可以到达的顶点因此C顶点从栈弹出 (栈内:B A)  --已经搜索到的C弹出(C)
8. 返回到栈顶B顶点查看还可以到达哪个顶点
9. 栈再放入D顶点 (栈内: D B A)
10. 搜索邻接矩阵中第四行D顶点可以到达哪个顶点
11. 没有可以到达的顶点因此D顶点从栈弹出 (栈内:B A) --已经搜索到的D弹出(C D)
12. 返回到栈顶B顶点查看还可以到达哪个顶点
13. 栈再放入E顶点 (栈内:E B A)
14. 搜索邻接矩阵中第五行E顶点可以到达哪个顶点
15. 没有可以到达的顶点因此E顶点从栈弹出 (栈内:B A) --已经搜索到的E弹出(C D E)
16. 五个顶点都被遍历过后弹出栈内元素(先出B后出A)
17. 最终遍历顺序是: A B E D C

广度优先搜索算法(BFS)

从当前顶点一条路走到死,走死顶点就出队。让屁股后面的顶点继续走到死

1. 队列先放入A顶点 (队列内:A)
2. 搜索邻接矩阵中第一行A顶点可以到达哪个顶点
3. 队列再放入B顶点 (队列内:B A)
4. 搜索邻接矩阵中第一行A顶点还可以到达哪个顶点 
5. 队列再放入C顶点 (队列内:C B A)
6. 现在A没有可以到达的顶点因此A顶点出队(队列内:C B) --已经搜索到的A出队(A)
7. 现在搜索B还可以到达哪些顶点
8. 队列再放入D顶点 (队列内:D C B)
9. 在搜索B还可以到达哪些顶点
10. 队列再放入E顶点 (队列内:E D C B)
11. 五个顶点都被遍历过后弹出栈顶元素(先出B后出C然后D最后E)
12. 最终遍历顺序是: A B C D E

代码实现

1
2



哈希表

哈希表

通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。


散列函数(映射函数)

满足计算简单分布均匀的两大原则

五大方法

1. 直接定址法:(像利用数组下标对照着定位放)  -- 计算简单但是分布可能不均匀
2. 数字分析法:(事先知道数据分布)  -- 比如电话号码/身份证号码只需要考虑后几位存放问题
3. 平方取中法:(将所存的数字平方之后取最中间的位)  -- 比如17*17=289 放到数组下标为8的位置(会冲突)
4. 取余法:(将所存的数字取余数)  -- 比如17%10=7放到数组下标为7的位置(会冲突)
5. 随机数法:(将所存的数字random()方法随便放)  --不建议使用(随便放进去的不好取出来)

散列冲突的解决方案

两大方法

1. 开放地址法
    1.1 线性探测法  -- 有冲突的就 依次向后找空位放
    1.2 二次探测法  -- 有冲突的就 按照1的平方 2的平方 ..找空位放
    1.3 再哈希法    -- 使用两个散列函数存放 
2. 链地址法(HashMap底层)
    数组+链表的形式:(在数组下标对应的数组相当于建立一个链表,把符合相应条件的按照顺序指向)

,