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)暴力解法:列举所有的子串,判断是否为回文串,保存最长的回文串。
//时间复杂度:两层 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);
}
}
}
- 华为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;
}
}
}
}
}