剑指offer题目实现41~50(java实现)

面试题41:数据流中的中位数

int i = 0;
//遍历找到插入点
for(i; i < val.size(); i++){
    if(num <= val.get(i))
        break;
}
//插入相应位置
val.add(i, num);
import java.util.*;
public class Solution {
    private ArrayList<Integer> val = new ArrayList<Integer>();
    public void Insert(Integer num) {
        if(val.isEmpty())
            //val中没有数据,直接加入
            val.add(num); 
        //val中有数据,需要插入排序
        else{ 
            int i = 0;
            //遍历找到插入点
            for(i; i < val.size(); i++){
                if(num <= val.get(i))
                   break;
            }
            //插入相应位置
            val.add(i, num); 
        }
    }

    public Double GetMedian() {
        int n = val.size();
        //奇数个数字
        if(n % 2 == 1) 
            //类型转换
            return (double)val.get(n / 2); 
        //偶数个数字
        else{ 
            double a = val.get(n / 2);
            double b = val.get(n / 2 - 1);
            return (a + b) / 2;
        }
    }
}

堆排序时间复杂度 O(Nlog2N)

import java.util.*;
public class Solution {
    //小顶堆,元素数值都比大顶堆大
    private PriorityQueue<Integer> max = new PriorityQueue<>();
    //大顶堆,元素数值较小 
    private PriorityQueue<Integer> min = new PriorityQueue<>((o1, o2)->o2.compareTo(o1)); 
    //维护两个堆,取两个堆顶部即与中位数相关
    public void Insert(Integer num) {
        //先加入较小部分
        min.offer(num);
        //将较小部分的最大值取出,送入到较大部分
        max.offer(min.poll());  
        //平衡两个堆的数量
        if(min.size() < max.size())  
            min.offer(max.poll());
    }

    public Double GetMedian() {
        //奇数个
        if(min.size() > max.size()) 
            return (double)min.peek();
        else
            //偶数个
            return (double)(min.peek() + max.peek()) / 2; 
    }
}

面试题42:连续子数组的最大和

import java.util.*;
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        //记录到下标i为止的最大连续子数组和
        int[] dp = new int[array.length]; 
        dp[0] = array[0];
        int maxsum = dp[0];
        for(int i = 1; i < array.length; i++){
            //状态转移:连续子数组和最大值
            dp[i] = Math.max(dp[i - 1] + array[i], array[i]); 
            //维护最大值
            maxsum = Math.max(maxsum, dp[i]); 
        }
        return maxsum;
    }
}
import java.util.*;
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int x = array[0];
        int y = 0;
        int maxsum = x;
        for(int i = 1; i < array.length; i++){
            //状态转移:连续子数组和最大值
            y = Math.max(x + array[i], array[i]); 
            //维护最大值
            maxsum = Math.max(maxsum, y); 
            //更新x的状态
            x = y; 
        }
        return maxsum;
    }
}

面试题43:1~n整数中1出现的次数

import java.util.*;
public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int res = 0;
        //MulBase = 10^i
        long MulBase = 1;
        //每位数按照公式计算
        for(int i = 0; MulBase <= n; i++){ 
            //根据公式添加
            res += (n / (MulBase * 10)) * MulBase + 
                Math.min(Math.max(n % (MulBase * 10) - MulBase + 1, (long)0), MulBase);
            //扩大一位数
            MulBase *= 10; 
        }
        return res;
    }
}
import java.util.*;
public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int res = 0;
        //遍历1-n
        for(int i = 1; i <= n; i++){ 
            //遍历每个数的每一位
            for(int j = i; j > 0; j = j / 10){ 
                //遇到数字1计数
                if(j % 10 == 1) 
                    res++;
            }
        }
        return res;
    }
}

面试题44:数字序列中某一位的数字

//最开始想的两种方法
//题目理解错了
//1.char charAt(int index) 方法:得到指定位置的字符
import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 
     * @return int整型
     */
    public int findNthDigit (int n, String str) {
        // write code here
        return (int)str.charAt(n - 1) - (int)"0";
    }
}


//2.字符串转化成字符串数组,然后按索引取值转换

char类型转换成int类型:

  • 方法一:

第一种利用Integer包装类的方法Integer.parseInt;

 char ch = '9';
if (Character.isDigit(ch)){  // 判断是否是数字
    int num = Integer.parseInt(String.valueOf(ch));
    System.out.println(num);
}    
  • 方法二:

第二种方法利用字符强制转化为int型时,转化为ASCII码的特点。其字符的ASCII码值减去0的ASCII码值等于数值本身

 char ch = '9';
if (Character.isDigit(ch)){  // 判断是否是数字
    int num = (int)ch - (int)('0');
    System.out.println(num);
}
import java.util.*;
public class Solution {
    public int findNthDigit (int n) {
        //记录n是几位数
        int digit = 1;
        //记录当前位数区间的起始数字:1,10,100...
        long start = 1; 
        //记录当前区间之前总共有多少位数字
        long sum = 9; 
        //将n定位在某个位数的区间中
        while(n > sum){
            n -= sum;
            start *= 10; 
            digit++; 
            //该区间的总共位数
            sum = 9 * start * digit;
        }
        //定位n在哪个数字上
        String num = "" + (start + (n - 1) / digit);
        //定位n在数字的哪一位上
        int index = (n - 1) % digit;
        return (int)(num.charAt(index)) - (int)('0');
    }
}
import java.util.*;
public class Solution {
    public int findNthDigit (int n) {
        //记录n是几位数
        int i = 1; 
        while(i * Math.pow(10, i) < n){
            //前面添0增加的位
            n += Math.pow(10, i);
            i++;
        }
        String num = "" + (n / i);
        //根据除法锁定目标数字,根据取模锁定位置
        return (int)(num.charAt(n % i)) - (int)('0');
    }
}

面试题45:把数组排成最小的数

bool cmp(string& x, string& y){
    //叠加
    return x + y < y + x;
}
import java.util.*;
public class Solution {
    public String PrintMinNumber(int [] numbers) {
        //空数组的情况
        if(numbers == null || numbers.length == 0)
            return "";
        String[] nums = new String[numbers.length];
        //将数字转成字符
        for(int i = 0; i < numbers.length; i++)
            nums[i] = numbers[i] + "";
        //按照重载排序
        Arrays.sort(nums, new Comparator<String>() {
            public int compare(String s1, String s2) {
                return (s1 + s2).compareTo(s2 + s1);
            }
        });
        StringBuilder res = new StringBuilder();
        //字符串叠加
        for(int i = 0; i < nums.length; i++)
            res.append(nums[i]);
        return res.toString();
    }
}

JAVA 数组转字符串

在数组类中并没有对此方法重写(override),仅仅是重载(overload)为类的静态方法。

所以数组转为字符串应写成:Arrays.toString(a)

数组转字符串一般而言有三种方法:

一、遍历String[] arr = { "0", "1", "2", "3", "4", "5" };// 遍历

StringBuffer str5 = new StringBuffer();for (String s : arr) {

str5.append(s);

}

System.out.println(str5.toString()); // 012345

二、使用StringUtils的join方法//数组转字符串 org.apache.commons.lang3.StringUtils

String str3 = StringUtils.join(arr); // 数组转字符串,其实使用的也是遍历

System.out.println(str3); // 012345

String str4 = StringUtils.join(arr, ","); // 数组转字符串(逗号分隔)(推荐)

System.out.println(str4); // 0,1,2,3,4,5

三、使用ArrayUtils的toString方法// 数组转字符串 org.apache.commons.lang3.ArrayUtils

String str2 = ArrayUtils.toString(arr, ","); // 数组转字符串(逗号分隔,首尾加大括号)

System.out.println(str2); // {0,1,2,3,4,5}

import java.util.*;
public class Solution {
    public String PrintMinNumber(int [] numbers) {
        //空数组的情况
        if(numbers == null || numbers.length == 0)
            return "";
        String[] nums = new String[numbers.length];
        //将数字转成字符
        for(int i = 0; i < numbers.length; i++)
            nums[i] = numbers[i] + "";
        //冒泡排序
        for(int i = 0; i < nums.length - 1; i++){
            for(int j = 0; j < nums.length - i - 1; j++){
                String s1 = nums[j] + nums[j + 1];
                String s2 = nums[j + 1] + nums[j];
                //比较拼接的大小交换位置
                if(s1.compareTo(s2) > 0){
                    String temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
        }
        StringBuilder res = new StringBuilder();
        //字符串叠加
        for(int i = 0; i < nums.length; i++)
            res.append(nums[i]);
        return res.toString();
    }
}

面试题46:把数字翻译成字符串

import java.util.*;

public class Solution {
    /**
     * 解码
     * @param nums string字符串 数字串
     * @return int整型
     */
    public int solve (String nums) {
        // write code here
        //排除0
        if(nums.equals("0")) 
            return 0;
        //排除只有一种可能的10 和 20
        if(nums == "10" || nums == "20") 
            return 1;
        //当0的前面不是1或2时,无法译码,0种
        for(int i = 1; i < nums.length(); i++){ 
            if(nums.charAt(i) == '0')
                if(nums.charAt(i - 1) != '1' && nums.charAt(i - 1) != '2')
                    return 0;
        }
        int[] dp = new int[nums.length() + 1];
        //辅助数组初始化为1
        //辅助数组全部用1填充
        Arrays.fill(dp, 1); 
        for(int i = 2; i <= nums.length(); i++){
            //在11-19,21-26之间的情况
            if((nums.charAt(i - 2) == '1' && nums.charAt(i - 1) != '0') 
                || (nums.charAt(i - 2) == '2' && nums.charAt(i - 1) > '0' 
                && nums.charAt(i - 1) < '7'))
               dp[i] = dp[i - 1] + dp[i - 2];
            else
                dp[i] = dp[i - 1];
        }
        return dp[nums.length()];
    }
}
public class Solution {
    public int solve (String nums) {
        return back(nums.toCharArray(), 0);
    }
    // 递归函数
    public int back(char[] nums, int start){
        //当start走到终点时,证明已经解码完毕,直接返回1
        if(start == nums.length){
            return 1;
        }    
        //当字符为0的时候,0没对应的解码,所以直接返回0 (此路解码废掉)
        if(nums[start] == '0')
            return 0;
        //每次解码一个字符
        int res1 = back(nums,start+1);
        int res2 = 0;

        //如果当前字符等于1 或者 当前字符加上下一个字符合起来小于等于26 则可以一次解码两个字符
        if((start < nums.length-1) 
    && (nums[start] == '1' || (nums[start] == '2' &&nums[start+1] <= '6'))){
            res2 = back(nums,start+2);
        }
        //返回结果
        return res1 + res2;
    }
}

面试题47:礼物的最大价值

import java.util.*;
public class Solution {
    public int maxValue (int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        //第一列只能来自上方
        for(int i = 1; i < m; i++)
            grid[i][0] += grid[i - 1][0];
        //第一行只能来自左边
        for(int i = 1; i < n; i++)
            grid[0][i] += grid[0][i - 1];
        //遍历后续每一个位置
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++)
                //增加来自左边的与上边的之间的较大值
                grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
        return grid[m - 1][n - 1];
    }
}
import java.util.*;
public class Solution {
    private int recursion(int[][] grid, int m, int n, int[][] dp){
        //到达起点,停止递归
        if(m == 0 && n == 0){
            dp[0][0] = grid[0][0];
            return grid[0][0];
        }
        //两个边界
        if(m == 0)
            dp[0][n] = grid[0][n] + recursion(grid, m, n - 1, dp);
        if(n == 0)
            dp[m][0] = grid[m][0] + recursion(grid, m - 1, n, dp);
        //如果有值可以直接返回
        if(dp[m][n] == 0)
            //递归求左边或者上边的最大值
            dp[m][n] = grid[m][n] + 
        Math.max(recursion(grid, m - 1, n, dp), recursion(grid, m, n - 1, dp));
        return dp[m][n];
    }

    public int maxValue (int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        //用于记忆递归过程中的值
        int[][] dp = new int[m][n];
        return recursion(grid, m - 1, n - 1, dp);
    }
}

面试题48:最长不含重复字符的子字符串

while(mp.get(s.charAt(right)) > 1) 
    //窗口左移,同时减去该数字的出现次数
    mp.put(s.charAt(left), mp.get(s.charAt(left++)) - 1);  
import java.util.*;
public class Solution {
    public int lengthOfLongestSubstring (String s) {
        //哈希表记录窗口内非重复的字符
        HashMap<Character, Integer> mp = new HashMap<>();
        int res = 0;
        //设置窗口左右边界
        for (int left = 0, right = 0; right < s.length(); right++) {
            //窗口右移进入哈希表统计出现次数
            if (mp.containsKey(s.charAt(right)))
                mp.put(s.charAt(right), mp.get(s.charAt(right)) + 1);
            else
                mp.put(s.charAt(right), 1);
            //出现次数大于1,则窗口内有重复
            while (mp.get(s.charAt(right)) > 1)
                //窗口左移,同时减去该字符的出现次数
                mp.put(s.charAt(left), mp.get(s.charAt(left++)) - 1);
            //维护子串长度最大值
            res = Math.max(res, right - left + 1);
        }
        return res;
    }
}
import java.util.*;
public class Solution {
    public int lengthOfLongestSubstring (String s) {
        //哈希表记录窗口内非重复的字符及其下标
        HashMap<Character, Integer> mp = new HashMap<>();
        int res = 0;
        //dp[i]表示以下标i结尾的字符串最长不含重复子串的长度
        int[] dp = new int[s.length() + 1];
        for (int i = 1; i <= s.length(); i++) {
            dp[i] = 1;
            //哈希表中没有,说明不重复
            if (!mp.containsKey(s.charAt(i - 1)))
                //前一个加1
                dp[i] = dp[i - 1] + 1;
            //遇到重复字符
            else
                dp[i] = Math.min(dp[i - 1] + 1, i - mp.get(s.charAt(i - 1)));
            //加入哈希表
            mp.put(s.charAt(i - 1), i);
            //维护最大值
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

面试题49:丑数

public int GetUglyNumber_Solution(int index) {
    //1 2 3 4 5 6 8
    if (index <= 6)
        return index;   // 加快程序输出

    // 三个变量 后面有大作用!
    int i2 = 0, i3 = 0, i5 = 0;
    int[] res = new int[index];
    res[0] = 1;  // 第一个丑数为 1

    for (int i = 1; i < index; i++) {
        // 得到下一个丑数,三者中最小的
        res[i] = Math.min(res[i2] * 2, Math.min(res[i3] * 3, res[i5] * 5));
        /*第一次是 2、3、5比较,得到最小的是2*/
        /*第二次是 4、3、5比较,为什么是4了呢?
        因为上次2已经乘了一次了,所以接下去可以放的丑数在4、3、5之间*/
        // 所以开头的三个指针就是来标记2 3 5 乘的次数的
        if (res[i] == res[i2] * 2)
            i2++;
        if (res[i] == res[i3] * 3)
            i3++;
        if (res[i] == res[i5] * 5)
            i5++;
    }
    return res[index - 1];
}
 public static void main(String[] args) {
        long start = System.currentTimeMillis();
        System.out.println( getNumber(50));
        long end = System.currentTimeMillis();
        System.out.println(end - start);


    }
    
    private static int getNumber(int n){
        int x= 1;
        int i= 0;
        while (true){
            if(isNeedNum(x)){
                i++;
                if(i==n){
                    return x;
                }
            }
            x++;
        }
    }

    private static boolean isNeedNum(int j){
        int x= j;
        while (x%2==0){
            x=x/2;
        }
        while (x%3==0){
            x=x/3;
        }
        while (x%5==0){
            x=x/5;
        }
        if(x==1){
            return true;
        }
        return false;
    }

面试题50:第一个只出现一次的字符

import java.util.*;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        //异常检测
        if(str == null || str.length() == ){
            return -1;
        }
        
        HashMap<Character, Integer> mp = new HashMap<>();
        //统计每个字符出现的次数
        for(int i = 0; i < str.length(); i++) 
            //getOrDefault()  
            //获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值
            mp.put(str.charAt(i), mp.getOrDefault(str.charAt(i), 0) + 1);
        //找到第一个只出现一次的字母
        for(int i = 0; i < str.length(); i++) 
            if(mp.get(str.charAt(i)) == 1)
                return i;
        //没有找到
        return -1; 
    }
}
//位置置为-1
mp[str[i]] = -1;
while(!q.empty() && mp[q.front().first] == -1) 
    q.pop();
import java.util.*;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        //统计字符出现的位置
        HashMap<Character, Integer> mp = new HashMap<>();
        Queue<Character> q1 = new LinkedList<>();
        Queue<Integer> q2 = new LinkedList<>();
        for(int i = 0; i < str.length(); i++){
            //没有出现过的字符
            if(!mp.containsKey(str.charAt(i))){ 
                mp.put(str.charAt(i), i);
                q1.offer(str.charAt(i));
                q2.offer(i);
            //找到重复的字符
            }else{ 
                //位置置为-1
                mp.put(str.charAt(i), -1);
                //弹出前面所有的重复过的字符
                while(!q1.isEmpty() && mp.get(q1.peek()) == -1){
                    q1.poll();
                    q2.poll();
                }
            }
        }
        return q2.isEmpty() ? -1 : q2.poll();    
    }
}
//题目:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从
//字符流中只读出前两个字符"go"时,第一个只出现一次的字符是'g'。当从该字
//符流中读出前六个字符"google"时,第一个只出现一次的字符是'l'。
 
public class FirstCharacterInStream {
    private int index;
    private int[] occurence;
     
    public FirstCharacterInStream() {  //在构造函数中初始化成员变量
        index=0;
        occurence = new int[256];
        for(int i=0;i<256;i++) {
            //哈希表的值都初始化为1
            occurence[i]=-1;
        }
    }
     
    public void insert(char ch) {
        if(occurence[(int)ch]==-1) {
            occurence[(int)ch]=index;   //第一次出现
        }else if(occurence[(int)ch]>=0) {
            occurence[(int)ch]=-2;   //已经出现过了
        }
        index++;
    }
     
    public char getFirst() {
        int minIndex=Integer.MAX_VALUE;  //最大的integer
        //# ascii 值 35
        char ch='#';
        for(int i=0;i<256;i++) {
            if(occurence[i]>=0 && occurence[i]<minIndex) {
                ch = (char) i;
                minIndex=occurence[i];
            }
        }
        return ch;
    }
}
public static void main(String[] args) {
    //字符转化为ASCII码
    char ch_a = 'a';
    int code_a = (int)ch_a; // =ASCII码97
     
    //ASCII码转化为字符
    char copyCh_a = (char) code_a;  // =ASCII码97对应的字符'a'
     
    //字符形式数字转化为整型
    char c1 = '2';
    int n1 = c1-'0';  //=2, 由'2'和'1'的ASCII码相减得到
     
    //数字转化为字符形式
    char copyC1 = (char)(n1+'0');  //='2' ,由'0'的ASCII码加2得到'2'的ASCII码
    System.out.println(5);
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值