面试遇到的算法题

1.字符串转换整数

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 位有符号整数范围 [−231,  231 − 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231 − 1 的整数应该被固定为 231 − 1 。
  6. 返回整数作为最终结果。
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);
    }
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值