秋招刷题

1.岛屿问题
给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
 输入:
 11110
 11010
 11000
 00000
 输出: 1
示例 2:
 输入:
 11000
 11000
 00100
 00011
 输出: 3
解释: 每座岛屿只能由水平和/或竖直方向上相邻的陆地连接而成。

/*
具体思路看这个:
https://blog.youkuaiyun.com/Cherils/article/details/105633851?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.edu_weight&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.edu_weight
*/
import java.util.*;


public class IsLandDfs {
    public static int numIslands(int[][] grid) {
        //深度优先搜索 递归
        int res = 0;
        int m = grid.length;//行数
        //特殊情况
        if(grid == null ||m == 0) return 0;
        //因为当rown等于0时,coln根本算不出来,所以要先判断
        int n = grid[0].length; //列数

        for(int i = 0;i < m;i++){
            for(int j = 0; j < n; j++){
                if(grid[i][j] == 1){
                    res++;
                    //从(i,j)位置开始搜索,将搜索到的1值都标记为0,说明已经访问过,属于这次搜索的岛屿中的,下一次深度搜索已经不需要了。
                    dfs(i,j,grid);
                }
            }
        }
        return res;
    }
    public static void dfs(int i, int j,int[][] grid){
        int m = grid.length;//行数
        int n = grid[0].length; //列数
        //如果当前值已在边界外 或者当前值为0就直接返回,因为只需要搜索边界内的1值
        if(i >= m || j>=n || i < 0 || j < 0 || grid[i][j] == 0) return;
        //当当前访问到的(i,j)值标记为0,表示已访问过
        grid[i][j] = 0;
        //递归搜索它的四个邻接点
        dfs(i+1,j,grid);//下邻接点
        dfs(i-1,j,grid);//上邻接点
        dfs(i,j+1,grid);//右邻接点
        dfs(i,j-1,grid);//左邻接点
    }

    public static void main(String[] args) {

        // 岛屿 二维数组(图形化)
        int [][] isLand = {{1, 1, 0, 0, 0},{1, 1, 0, 0, 0},{0, 0, 1, 0, 0},{0, 0, 0, 1, 1}};
        int count = IsLandDfs.numIslands(isLand);
        System.out.println("一共探索到" + count + "座岛屿");
    }
}

2.背包问题

import java.util.*;

/**
 * 求解背包问题:
 * 给定 n 个背包,其重量分别为 w1,w2,……,wn, 价值分别为 v1,v2,……,vn
 * 要放入总承重为 totalWeight 的箱子中,
 * 求可放入箱子的背包价值总和的最大值。
 *
 * NOTE: 使用动态规划法求解 背包问题
 * 设 前 n 个背包,总承重为 j 的最优值为 v[n,j], 最优解背包组成为 b[n];
 * 求解最优值:
 * 1. 若 j < wn, 则 : v[n,j] = v[n-1,j];
 * 2. 若  j >= wn, 则:v[n,j] = max{v[n-1,j], vn + v[n-1,j-wn]}。
 *
 * 求解最优背包组成:
 * 1. 若 v[n,j] > v[n-1,j] 则 背包 n 被选择放入 b[n],
 * 2. 接着求解前 n-1 个背包放入 j-wn 的总承重中,
 *    于是应当判断 v[n-1, j-wn] VS v[n-2,j-wn], 决定 背包 n-1 是否被选择。
 * 3. 依次逆推,直至总承重为零。
 *
 *    重点: 掌握使用动态规划法求解问题的分析方法和实现思想。
 *    分析方法: 问题实例 P(n) 的最优解S(n) 蕴含 问题实例 P(n-1) 的最优解S(n-1);
 *              在S(n-1)的基础上构造 S(n)
 *    实现思想: 自底向上的迭代求解 和 基于记忆功能的自顶向下递归
 */
public class KnapsackProblem {


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {

            /* 1.读取数据 */

            int number = sc.nextInt(); // 物品的数量

            // 注意:我们声明数组的长度为"n+1",并另score[0]和time[0]等于0。
            // 从而使得 数组的下标,对应于题目的序号。即score[1]对应于第一题的分数,time[1]对应于第一题的时间
            int[] weight = new int[number + 1]; // {0,2,3,4,5} 每个物品对应的重量
            int[] value = new int[number + 1]; // {0,3,4,5,6} 每个物品对应的价值

            weight[0] = 0;
            for (int i = 1; i < number + 1; i++) {
                weight[i] = sc.nextInt();
            }

            value[0] = 0;
            for (int i = 1; i < number + 1; i++) {
                value[i] = sc.nextInt();
            }

            int capacity = sc.nextInt(); // 背包容量

            /* 2.求解01背包问题 */

            int[][] v = new int[number + 1][capacity + 1];// 声明动态规划表.其中v[i][j]对应于:当前有i个物品可选,并且当前背包的容量为j时,我们能得到的最大价值

            // 填动态规划表。当前有i个物品可选,并且当前背包的容量为j。
            for (int i = 0; i < number + 1; i++) {
                for (int j = 0; j < capacity + 1; j++) {
                    if (i == 0) {
                        v[i][j] = 0; // 边界情况:边界情况:若只有0个背包,那只能得到价值为0。所以令V(0,j)=0
                    } else if (j == 0) {
                        v[i][j] = 0; // 边界情况:边界情况:若背包容量为0,那只能得到价值为0。所以令V(i,0)=0
                    } else {
                        if (j < weight[i]) {
                            v[i][j] = v[i - 1][j];// 包的容量比当前该物品体积小,装不下,此时的价值与前i-1个的价值是一样的,即V(i,j)=V(i-1,j);
                        } else {
                            v[i][j] = Math.max(v[i - 1][j], v[i - 1][j - weight[i]] + value[i]);// 还有足够的容量可以装当前该物品,但装了当前物品也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}。
                        }
                    }
                }
            }

            System.out.println();
            System.out.println("动态规划表如下:");
            for (int i = 0; i < number + 1; i++) {
                for (int j = 0; j < capacity + 1; j++) {
                    System.out.print(v[i][j] + "\t");
                }
                System.out.println();
            }
            System.out.println("背包内最大的物品价值总和为:" + v[number][capacity]);// 有number个物品可选,且背包的容量为capacity的情况下,能装入背包的最大价值

            /* 3.价值最大时,包内装入了哪些物品? */

            int[] item = new int[number + 1];// 下标i对应的物品若被选中,设置值为1
            Arrays.fill(item, 0);// 将数组item的所有元素初始化为0

            // 从最优解,倒推回去找
            int j = capacity;
            for (int i = number; i > 0; i--) {
                if (v[i][j] > v[i - 1][j]) {// 在最优解中,v[i][j]>v[i-1][j]说明选择了第i个商品
                    item[i] = 1;
                    j = j - weight[i];
                }
            }

            System.out.print("包内物品的编号为:");
            for (int i = 0; i < number + 1; i++) {
                if (item[i] == 1) {
                    System.out.print(i + " ");
                }
            }
            System.out.println("----------------------------");
        }
    }
}

3.全排列问题

import java.util.*;
/*
全排列问题
思路:只有一个元素的全排列就是这个元素本身,所以依次把每个元素放到第一个位置上,
剩下的元素进行全排列,进行层层递归。
 */
public class Perm {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextInt()){
            int number = sc.nextInt();
            int[] arr = new int[number];
            for(int i=0;i<arr.length;i++){
                arr[i] = sc.nextInt();
            }
            perm(arr,0,arr.length-1);
        }
    }
    public static void perm(int[] arr,int start,int end){
        if(start == end){
            System.out.println(Arrays.toString(arr));
        }
        else{
            for(int i=start;i<=end;i++){
                swap(arr,start,i);
                perm(arr,start+1,end);
                swap(arr,start,i);
            }
        }
    }
    public static void swap(int[] arr,int start,int i){
        int temp = arr[start];
        arr[start] = arr[i];
        arr[i] = temp;
    }
}

4.组合数

import java.util.*;
/*
递归方法求组合问题,n个数中取k个数,求所有的组合。

这题要求的是从n个数字中选出k个弄成一组合,问最后总共有多少种组合,
如果用数学知识就是C(n,k),这个公式又可以表示为C(n,k)=C(n-1,k-1)+C(n-1,k),
也就是说要么选第n个数字,要么不选第n个数字。

(1),选第n个数字
如果选第n个数字,我们需要从前面n-1个数字中选择k-1个,然后在和数字n组合

(2),不选第n个数字
如果不选第n个数字,我们可以直接从前面n-1个数字中选择k个即可
 */
public class Combine {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextInt()){
            int n = sc.nextInt();
            int k = sc.nextInt();
            ArrayList<ArrayList<Integer>> arr = combine(n,k);
            for(int i=0;i<arr.size();i++){
                ArrayList<Integer> temp = arr.get(i);
                for(int j=0;j<temp.size();j++){
                    System.out.print(temp.get(j)+" ");
                }
                System.out.println();
            }
        }
    }
    public static ArrayList<ArrayList<Integer>> combine(int n,int k){
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        if(n<k||k==0){
            return res;
        }
        res = combine(n-1,k-1);
        if(res.isEmpty()){
            ArrayList<Integer> temp = new ArrayList<Integer>();
            res.add(temp);
        }
        for(int i=0;i<res.size();i++){
            res.get(i).add(n);
        }
        res.addAll(combine(n-1,k));
        return res;
    }
}
  1. 最长回文字符串

(1)暴力解法:列举所有的子串,判断是否为回文串,保存最长的回文串。

//时间复杂度:两层 for 循环 O(n²),for 循环里边判断是否为回文 O(n),所以时间复杂度为 O(n³)
import java.util.*;

public class LongestPalindrome1 {
    public static void longestPalindrome(String s){
        String res = "";
        int max = 0;
        for(int i=0;i<s.length();i++){
            for(int j=i+1;j<=s.length();j++){
                String temp = s.substring(i,j);
                if(isPalindrome(temp) && (j-i)>max){
                    res = temp;
                    max = j-i;
                }
            }
        }
        System.out.println("最长回文字符串为: "+res);
        System.out.println("最长回文字符串的长度为: "+max);
    }
    public static boolean isPalindrome(String temp){
        for(int i=0;i<temp.length()/2;i++){
            if(temp.charAt(i) != temp.charAt(temp.length()-1-i)){
                return false;
            }
        }
        return true;
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            String s = sc.next();
            LongestPalindrome1.longestPalindrome(s);
        }
    }
}

(2)我们知道回文串一定是对称的,所以我们可以每次循环选择一个中心,进行左右扩展,判断左右字符是否相等即可。由于存在奇数的字符串和偶数的字符串,所以我们需要从一个字符开始扩展,或者从两个字符之间开始扩展,所以总共有n + (n-1)个中心。

import java.util.*;

public class LongestPalindrome2 {

    public static void longestPalindrome(String s){
        if(s == null || s.length() == 0){
            System.out.println("字符串为空");
        }
        int start=0,end=0;
        for(int i=0;i<s.length();i++){
            int len1 = isPalindrome(s,i,i);
            int len2  = isPalindrome(s,i,i+1);
            int max = Math.max(len1,len2);
            if(max>end-start+1){
                start = i-(max-1)/2;
                end = i+max/2;
            }
        }
        String res = s.substring(start,end+1);
        System.out.println("最长回文字符串为: "+res);
        System.out.println("最长回文字符串的长度为: "+res.length());
    }
    public static int isPalindrome(String s,int low,int high){
        int L = low;
        int R = high;
        while(L>=0 && R<s.length() && s.charAt(L)==s.charAt(R)){
            L--;
            R++;
        }
        return (R-1)-(L+1)+1;
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            String s = sc.next();
            LongestPalindrome2.longestPalindrome(s);

        }
    }
}
  1. 华为9.2笔试第一题

1、幼儿园小朋友站成一列,按位置1、2、3…顺序编号,每个小朋友都拿了若干糖果,请找出3个小朋友,他们拿着相同颜色的糖果,且他们拿的糖果总数不少于其他任何小朋友(拿相同颜色的糖果)的糖果总数,如果存在多组这样的小朋友,则找出位置编号最小的小朋友所在的组。

设置的前提条件:

(1)每个小朋友最少拿一颗糖,最多拿1024颗糖,且只拿一种颜色的糖果;不存在两个小朋友拿相同颜色相同树木的糖果。

(2)糖果颜色只有2种:1为红色,2为蓝色。

输出描述:

拿相同颜色且糖果总数最多的3位小朋友位置编号,糖果颜色及总数;第一行为3个小朋友位置编号(糖果数从小到大对应的位置编号) ,第二行为糖果颜色,第三行为糖果总数。

如果没有满足条件的小朋友,则输出字符串“null”。

示例1:

输入

6

2 2

2 1

3 2

5 2

3 1

7 2

输出

3 4 6

2

15

import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextInt()){
            int n = sc.nextInt();
            int []num = new int[n];
            int []type = new int[n];
            int cnt =0;
            for(int i=0;i<n;i++){
                num[i]=sc.nextInt();
                type[i]=sc.nextInt();
                if(type[i]==1) cnt++;
            }
            //四个数组可以用两个treemap代替
            int []n1 =new int[cnt];
            int[]t1 = new int[cnt];
            int[] n2 = new int[n-cnt];
            int[] t2 = new int[n-cnt];
            int top1=0,top2=0,t11=0,t22=0;
            for(int i=0;i<n;i++){
                if(type[i]==1){
                    n1[top1++] = num[i];
                    t1[t11++] = i+1;//注意这里是从第1行开始的
                }else if(type[i]==2){
                    n2[top2++] = num[i];
                    t2[t22++] = i+1;
                }
            }
            if(cnt<3&&n-cnt<3) {//没满足情况
                System.out.println("null");
                continue;
            }
            if(cnt < 3){
                helper(n2,t2);
                System.out.println(t2[t2.length-3]+" "+t2[t2.length-2]+" "+t2[t2.length-1]);
                System.out.println(2);
                System.out.println(n2[n2.length-1]+n2[n2.length-2]+n2[n2.length-3]);

            }
            else if(n-cnt<3){
                helper(n1,t1);
                System.out.println(t1[t1.length-3]+" "+t1[t1.length-2]+" "+t1[t1.length-1]);
                System.out.println(1);
                System.out.println(n1[n1.length-1]+n1[n1.length-2]+n1[n1.length-3]);
            }
            else{//两个种类礼物的人都>=3
                helper(n2,t2);
                helper(n1,t1);
                if(n2[n2.length-1]+n2[n2.length-2]+n2[n2.length-3] > n1[n1.length-1]+n1[n1.length-2]+n1[n1.length-3]){//比较总量谁大
                    System.out.println(t2[t2.length-3]+" "+t2[t2.length-2]+" "+t2[t2.length-1]);
                    System.out.println(2);
                    System.out.println(n2[n2.length-1]+n2[n2.length-2]+n2[n2.length-3]);
                }
                else if(n2[n2.length-1]+n2[n2.length-2]+n2[n2.length-3] < n1[n1.length-1]+n1[n1.length-2]+n1[n1.length-3]){
                    System.out.println(t1[t1.length-3]+" "+t1[t1.length-2]+" "+t1[t1.length-1]);
                    System.out.println(1);
                    System.out.println(n1[n1.length-1]+n1[n1.length-2]+n1[n1.length-3]);
                }
                else{
                    if(t2[t2.length-3] > t1[t1.length-3]){//总量相等比较序号
                        System.out.println(t1[t1.length-3]+" "+t1[t1.length-2]+" "+t1[t1.length-1]);
                        System.out.println(1);
                        System.out.println(n1[n1.length-1]+n1[n1.length-2]+n1[n1.length-3]);
                    }
                    else{
                        System.out.println(t2[t2.length-3]+" "+t2[t2.length-2]+" "+t2[t2.length-1]);
                        System.out.println(2);
                        System.out.println(n2[n2.length-1]+n2[n2.length-2]+n2[n2.length-3]);
                    }
                }

            }
        }
    }

    public static void helper(int[] n,int[] t){//此过程完全可以用treemap自动完成
        for(int i=0;i<n.length;i++){
            for (int j = 0; j <n.length-i-1 ; j++) {
                if(n[j]>n[j+1]){
                    int t1 = n[j];
                    n[j] = n[j+1];
                    n[j+1]=t1;
                    int x = t[j];
                    t[j] = t[j+1];
                    t[j+1] = x;
                }
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值