1.字符串转换整数
- 读入字符串并丢弃无用的前导空格
- 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
- 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
- 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为
0
。必要时更改符号(从步骤 2 开始)。 - 如果整数数超过 32 位有符号整数范围
[−231, 231 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于−231
的整数应该被固定为−231
,大于231 − 1
的整数应该被固定为231 − 1
。 - 返回整数作为最终结果。
class Solution {
public int myAtoi(String s) {
if(s.length() == 0)return 0;
int index = 0,n = s.length(),sign = 1,res = 0;
//处理前置空格
while(index < n && s.charAt(index) == ' ') index++;
//处理符号
if(index < n && (s.charAt(index)=='+' || s.charAt(index)=='-')){
sign = s.charAt(index++) == '+'?1:-1;
}
//处理数字
while(index<n && Character.isDigit(s.charAt(index))){
int digit = s.charAt(index) - '0';
//判断是否溢出
if(res > (Integer.MAX_VALUE - digit)/10){
return sign == 1? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
res = res*10 + digit;
index++;
}
return res*sign;
}
}
2.求岛屿周长
给定一个 row x col
的二维网格地图 grid
,其中:grid[i][j] = 1
表示陆地, grid[i][j] = 0
表示水域。
网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。
岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。
思路:直接暴力解法,简单易懂:求边长,其实就是判断每个陆地的四周是什么,从上下左右四个方向找,遇到非陆地就可以+1(其实本题的dfs解法也是这个道理,个人感觉没必要用dfs去做搜索)
class Solution {
public int islandPerimeter(int[][] grid) {
int sum = 0;
for(int i=0;i<grid.length;i++){
for(int j=0;j<grid[0].length;j++){
if(grid[i][j] == 1) sum = dfs(grid,i,j);
}
}
return sum;
}
public int dfs(int[][] grid,int i,int j){
if(i<0 || i>=grid.length || j<0 || j>=grid[0].length || grid[i][j] == 0)return 1;
if(grid[i][j] == -1)return 0;
grid[i][j] = -1;
int count = 0;
count += dfs(grid,i+1,j);
count += dfs(grid,i,j+1);
count += dfs(grid,i-1,j);
count += dfs(grid,i,j-1);
return count;
}
}
3.设计微信抢红包算法
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
/*Random 随机生成一个区间在[min , max]的数值
randNumber 将被赋值为一个 MIN 和 MAX 范围内的随机数
int randNumber =rand.nextInt(MAX - MIN + 1) + MIN; */
/**
* 生成min到max范围的浮点数
**/
public static double nextDouble(final double min, final double max) {
return min + ((max - min) * new Random().nextDouble());
}
public static String format(double value) {
return new java.text.DecimalFormat("0.00").format(value); // 保留两位小数
}
//二倍均值法
public static List<Double> doubleMeanMethod(double money,int number){
List<Double> result = new ArrayList<Double>();
if(money<0&&number<1)
return null;
double amount,sum=0;
int remainingNumber=number;
int i=1;
while(remainingNumber>1){
amount= nextDouble(0.01,2*(money/remainingNumber));
sum+=amount;
System.out.println("第"+i+"个人领取的红包金额为:"+format(amount));
money -= amount;
remainingNumber--;
result.add(amount);
i++;
}
result.add(money);
System.out.println("第"+i+"个人领取的红包金额为:"+format(money));
sum+=money;
System.out.println("验证发出的红包总金额为:"+format(sum));
return result;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int number;
double money;
System.out.print("请输入红包总金额:");
money = sc.nextDouble();
System.out.print("请输入红包数量:");
number = sc.nextInt();
//System.out.println(money + " " + number);
//二倍均值法
doubleMeanMethod(money,number);
//System.out.println(doubleMeanMethod(money,number).toString());
//也是可以直接输出list的,为了观察方便,我就在循环中输出了,存在list里主要是为了后续方便数据的使用
System.out.println();
}
}
4.长度最小的子数组之和大于target
思路:滑动窗口+双指针遍历数组,创建一个sum表示子数组之和,然后累加,当sum的值大于等于target的时候,进入while循环,内部先计算最短长度,最短长度len初始化为最大值,然后每次进行比较len = Math.min(len,end-start+1),计算完之后收缩左边界就是sum-=nums[start],然后start++,直到不满足while条件位置。遍历结束后返回len
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int start = 0;
int len = Integer.MAX_VALUE;
int sum = 0;
for(int end = 0;end < n;end++){
sum += nums[end];
while(sum >= target){
len = Math.min(len,end-start+1);
sum-=nums[start];
start++;
}
}
return len==Integer.MAX_VALUE?0:len;
}
}
5.无重复字符的最长子串
思路:使用滑动窗口+双指针+哈希表的思路,哈希表用来记录遍历到的出现的字符的最后一次出现的位置,就是最远位置,然后指针双指针表示滑动窗口的左右边界,一开始遍历不断扩充右边界,直到遇到第一个重复字符,当遇到之后,把start的位置调整到Math.max(start,map.containsKey(s.charAt(i))+1)的位置,这里表示当前start的的位置和之前一次出现重复字符的位置的下一个的最大值,就是确保滑动窗口内部是无重复的且滑动窗口的移动不会出现退回。然后再计算长度len = Math.max(len,i-start+1);然后再把当前的字符和其下标添加到哈希表中。最后返回len
class Solution {
public int lengthOfLongestSubstring(String s) {
Map<Character,Integer> map = new HashMap<>();
int start = 0;
int len = 0;
for(int i=0;i<s.length();i++){
if(map.containsKey(s.charAt(i))){
start = Math.max(start,map.get(s.charAt(i))+1);
}
len = Math.max(len, i - start +1);
map.put(s.charAt(i),i);
}
return len;
}
}
6.比较版本号
思路:使用split方法直接将字符串按照指定的分隔符拆分成一个字符串数组,然后同时遍历这两个数组,创建变量x和y用来记录当前遍历到的字符,先转换为Int,然后比较大小,相等就继续遍历,x>y就return 1,x<y就return -1.遍历完之后如果都没返回就返回0;
class Solution {
public int compareVersion(String version1, String version2) {
String[] num1 = version1.split("\\.");
String[] num2 = version2.split("\\.");
for(int i=0;i<num1.length || i<num2.length;i++){
int x = 0,y = 0;
if(i < num1.length) x = Integer.parseInt(num1[i]);
if(i < num2.length) y = Integer.parseInt(num2[i]);
if(x > y)return 1;
if(x < y)return -1;
}
return 0;
}
}
7.最长回文子串
思路:
(1)动态规划:先创建一个boolean类型的二维数组用来表示以i为起点,j为结尾的子串是否是回文,然后设置最终的左右边界指针,left和right和子串长度res。遍历字符串,两层遍历,第一层遍历子串,第二层从第一层的位置开始向回遍历,判断i,j的长度子串是否为回文。如果s.charAt(i)==s.charAt(j)的同时,他的i+1,j-1数组也为回文,或者j-i长度小于1,那说明当前的i,j的长度也是回文,然后dp[i][j] = true。如果(j-i>res)那说明找到了当前遍历的最长回文子串,然后res = j-i;left = i;right = j。最后返回s.substring(left,right+1)
class Solution {
public String longestPalindrome(String s) {
int n = s.length();
int left = 0,right = 0,res = 0;
boolean[][] dp = new boolean[n][n];
for(int i=n-1;i>=0;i--){
for(int j=i;j<n;j++){
if(s.charAt(i) == s.charAt(j) && (j - i<=1 || dp[i+1][j-1])){
dp[i][j] = true;
if(j-i > res){
res = j-i;
left = i;
right = j;
}
}
}
}
return s.substring(left,right+1);
}
}
(2)中心扩展:
8.统计字符串中字母数量数量最多的字母,输出该字母和次数
思路:使用哈希表来存储字符出现字母的次数,用Character.isLetter来只遍历字母,然后遍历完字符串之后,创建两个变量,maxchar和maxcount,表示最多的字母和其数量。然后遍历哈希表,for(Map.Entry<Character,Integer> entry : map.entrySet())然后吧数量最多的提取出来,并返回。
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String str = "aaabbc"; // 你可以将这个字符串替换成任何需要测试的字符串
// 创建一个HashMap来存储字母和对应的计数
Map<Character, Integer> map = new HashMap<>();
for (char ch : str.toCharArray()) {
if (Character.isLetter(ch)) { // 只统计字母
ch = Character.toLowerCase(ch); // 转换为小写,统一处理
map.put(ch, map.getOrDefault(ch, 0) + 1);
}
}
// 寻找出现次数最多的字母
char maxChar = ' ';
int maxCount = 0;
for (Map.Entry<Character, Integer> entry : map.entrySet()) {
if (entry.getValue() > maxCount) {
maxCount = entry.getValue();
maxChar = entry.getKey();
}
}
System.out.println(maxChar+" "+maxCount);
}
}
9.将一组随机数组倒序输出
思路:排序,倒序输出
import java.io.*;
import java.util.*;
public class Main{
public static void main(String args[]){
int[] nums = {2,3,5,1,4,8,7,9,6,10};
quciksort(nums,0,nums.length-1);
int l = 0;
int r = nums.length-1;
while(l < r){
int tmp = nums[l];
nums[l] = nums[r];
nums[r] = tmp;
l++;r--;
}
for(int i=0;i<nums.length;i++) System.out.println(nums[i]);
}
public static void quciksort(int[] nums,int l,int r){
if(l > r)return;
int p = nums[l];
int i=l,j=r;
while(i<j){
while(i<j && nums[j]>p)j--;
nums[i] = nums[j];
while(i<j && nums[i]<=p)i++;
nums[j] = nums[i];
}
nums[i] = p;
quciksort(nums,l,i-1);
quciksort(nums,i+1,r);
}
}