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) 题目
分析 代码
结果
面试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结果 }
结果