Leetcode面T16(1-9)树

Q16.1 交换数字

编写一个函数,不用临时变量,直接交换numbers = [a, b]中a与b的值。

示例:

输入: numbers = [1,2]
输出: [2,1]
提示:

numbers.length == 2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-numbers-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int[] swapNumbers(int[] numbers) {
        numbers[0] = numbers[0] + numbers[1] - (numbers[1] = numbers[0]);
        return numbers;
    }
}

Q16.2 单词频率

设计一个方法,找出任意指定单词在一本书中的出现频率。

你的实现应该支持如下操作:

WordsFrequency(book)构造函数,参数为字符串数组构成的一本书
get(word)查询指定单词在书中出现的频率
示例:

WordsFrequency wordsFrequency = new WordsFrequency({"i", "have", "an", "apple", "he", "have", "a", "pen"});
wordsFrequency.get("you"); //返回0,"you"没有出现过
wordsFrequency.get("have"); //返回2,"have"出现2次
wordsFrequency.get("an"); //返回1
wordsFrequency.get("apple"); //返回1
wordsFrequency.get("pen"); //返回1
提示:

book[i]中只包含小写字母
1 <= book.length <= 100000
1 <= book[i].length <= 10
get函数的调用次数不会超过100000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/words-frequency-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

Map<String , Integer> map = new HashMap<>();
    public WordsFrequency(String[] book) {
        for(String s:book){
            map.put(s, map.getOrDefault(s, 0)+1);
        }
    }
    
    public int get(String word) {
        if(!map.containsKey(word))  return 0;
        return map.get(word);
    }

Q16.3 交点

给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。

要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。

 

示例 1:

输入:
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
输出: {0.5, 0}
示例 2:

输入:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出: {1, 1}
示例 3:

输入:
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
输出: {},两条线段没有交点
 

提示:

坐标绝对值不会超过 2^7
输入的坐标均是有效的二维坐标

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public double[] intersection(int[] start1, int[] end1, int[] start2, int[] end2) {
        //求两线段的最大点和最小点
        int xmin1 = start1[0] < end1[0] ? start1[0] : end1[0];
        int ymin1 = start1[1] < end1[1] ? start1[1] : end1[1];
        int xmin2 = start2[0] < end2[0] ? start2[0] : end2[0];
        int ymin2 = start2[1] < end2[1] ? start2[1] : end2[1];

        int xmax1 = start1[0] > end1[0] ? start1[0] : end1[0];
        int ymax1 = start1[1] > end1[1] ? start1[1] : end1[1];
        int xmax2 = start2[0] > end2[0] ? start2[0] : end2[0];
        int ymax2 = start2[1] > end2[1] ? start2[1] : end2[1];

        double x = 0;
        double y = 0;
        //如果两点在直线的同一侧,代入方程同号
        int f11 = fangcheng(start2[0],start2[1],start1[0],start1[1],end1[0],end1[1]);
        int f12 = fangcheng(end2[0],end2[1],start1[0],start1[1],end1[0],end1[1]);
        int f21 = fangcheng(start1[0],start1[1],start2[0],start2[1],end2[0],end2[1]);
        int f22 = fangcheng(end1[0],end1[1],start2[0],start2[1],end2[0],end2[1]);
        //两点在直线的同侧,没有交点
        if (f11 * f12 > 0 || f21*f22 > 0){
            return new double[0];
        }else if(f11 == f12 && f12 == f21 && f21 == f22){//四点共线
            // 没有交叉排列
            if (xmax1 < xmin2 || xmax2 < xmin1){
                return new double[0];
            }else if(xmax1 == xmin1 && xmin1 == xmax2 && xmax2 == xmin2){//垂直的线,判断y
                //没有交叉
                if (ymax1 < ymin2 || ymax2 < ymin1){
                    return new double[0];
                }else{
                    //取两个条线的小值中最大的,得交叉点小点
                    x = xmax1;
                    y = ymin1 > ymin2 ? ymin1 : ymin2;
                    return new double[]{x,y};
                }
            }else {
                //取两个条线的小值中最大的,得交叉点小点
                x = xmin1 > xmin2 ? xmin1 : xmin2;
                if (start1[0] == x){
                    y = start1[1];
                }else if(end1[0] == x){
                    y = end1[1];
                }else if (start2[0] == x){
                    y = start2[1];
                }else {
                    y = end2[1];
                }
                return new double[]{x,y};
            }
        }else{
            // 线段1垂直
            if (start1[0] == end1[0]){
                x = start1[0];
                double xue2 = 1.0*(start2[1] - end2[1])/(start2[0] - end2[0]);
                double b2 = end2[1] - xue2 * end2[0];
                y = xue2 * x + b2;
                return new double[]{x,y};
            }else if (start2[0] == end2[0]){//线段2垂直
                x = start2[0];
                double xue1 = 1.0*(start1[1] - end1[1])/(start1[0] - end1[0]);
                double b1 = end1[1] - xue1 * end2[0];
                y = xue1 * x + b1;
                return new double[]{x,y};
            }else {//通用情况,线段1和线段2都不垂直,计算斜率、常量值,y=a*x+b
                double xue1 = 1.0*(start1[1] - end1[1])/(start1[0] - end1[0]);//斜率1
                double xue2 = 1.0*(start2[1] - end2[1])/(start2[0] - end2[0]);//斜率2
                double b1 = end1[1] - xue1 * end1[0];//常量b1
                double b2 = end2[1] - xue2 * end2[0];//常量b2
                x = (b2 - b1)/(xue1 - xue2);
                y = xue1 * x + b1;
                return new double[]{x,y};
            }
        }
    }
    //验证两点是否在另一条直线的同一侧,同一侧同号,不同侧异号
    private int fangcheng(int x,int y,int x0,int y0,int x1,int y1){
        return (x-x0)*(y1-y0) - (x1-x0)*(y-y0);
    }
}

Q16.4 井字游戏

设计一个算法,判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘,由字符" ","X"和"O"组成,其中字符" "代表一个空位。

以下是井字游戏的规则:

玩家轮流将字符放入空位(" ")中。
第一个玩家总是放字符"O",且第二个玩家总是放字符"X"。
"X"和"O"只允许放置在空位中,不允许对已放有字符的位置进行填充。
当有N个相同(且非空)的字符填充任何行、列或对角线时,游戏结束,对应该字符的玩家获胜。
当所有位置非空时,也算为游戏结束。
如果游戏结束,玩家不允许再放置字符。
如果游戏存在获胜者,就返回该游戏的获胜者使用的字符("X"或"O");如果游戏以平局结束,则返回 "Draw";如果仍会有行动(游戏未结束),则返回 "Pending"。

示例 1:

输入: board = ["O X"," XO","X O"]
输出: "X"
示例 2:

输入: board = ["OOX","XXO","OXO"]
输出: "Draw"
解释: 没有玩家获胜且不存在空位
示例 3:

输入: board = ["OOX","XXO","OX "]
输出: "Pending"
解释: 没有玩家获胜且仍存在空位
提示:

1 <= board.length == board[i].length <= 100
输入一定遵循井字棋规则

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/tic-tac-toe-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    
    // 井字游戏
    public String tictactoe(String[] board) {
        int n = board.length;
        char[][] grid = new char[n][n];
        for (int i = 0; i < n; i++) {
            grid[i] = board[i].toCharArray();
        }
        int empty = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == ' ') empty++;
            }
        }
        if (empty > 0) {
            if (check(grid, 'X')) return "X";
            if (check(grid, 'O')) return "O";
            return "Pending";
        }
        if (check(grid, 'X')) return "X";
        if (check(grid, 'O')) return "O";
        return "Draw";
    }

    private boolean check(char[][] grid, char c) {
        int n = grid.length;
        // 检查行
        for (int row = 0; row < n; row++) {
            int col;
            for (col = 0; col < n; col++) {
                if (grid[row][col] != c) break;
            }
            if (col >= n) return true;
        }
        // 检查列
        for (int col = 0; col < n; col++) {
            int row;
            for (row = 0; row < n; row++) {
                if (grid[row][col] != c) break;
            }
            if (row >= n) return true;
        }
        // 主对角线
        int i;
        for (i = 0; i < n; i++) {
            if (grid[i][i] != c) break;
        }
        if (i >= n) return true;
        // 副对角线
        i = 0;
        for (; i < n; i++) {
            if (grid[i][n - 1 - i] != c) break;
        }
        return i >= n;
    }
}

Q16.5 阶乘尾数

设计一个算法,算出 n 阶乘有多少个尾随零。

示例 1:

输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:

输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/factorial-zeros-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int trailingZeroes(int n) {
        /*
         0 是由 *10 得到的,而 10 是由 2 * 5 得到的
         因此我们求 n! 过程中存在多少个 2 * 5
         因为 2 的个数必定比 5 的个数多,因此我们只求 5 的个数

         如果直接一个一个遍历,即 
         for(int i = 5; i <= n; i++){
            int temp = i;
            while(temp % 5 == 0){
                count++;
                temp /= 5;
            }
        }
        那么 n 过大时,从 1 遍历到 n, 那么会超时,因此我们修改下规律

        n! = 1 * 2 * 3 * 4 * (1 * 5) * ... * (2 * 5) * ... * (3 * 5) ...
        我们发现,
        每隔 5 个数就会出现 一个 5,因此我们只需要通过 n / 5 来计算存在存在多少个 5 个数,那么就对应的存在多少个 5
        但是,我们也会发现
        每隔 25 个数会出现 一个 25, 而 25 存在 两个 5,我们上面只计算了 25 的一个 5,因此我们需要 n / 25 来计算存在多少个 25,加上它遗漏的 5
        同时,我们还会发现
        每隔 125 个数会出现一个 125,而 125 存在 三个 5,我们上面只计算了 125 的两个 5,因此我们需要 n / 125 来计算存在多少个 125,加上它遗漏的 5
        ...

        因此我们 count = n / 5 + n / 25 + n / 125 + ...
        最终分母可能过大溢出,上面的式子可以进行转换

        count = n / 5 + n / 5 / 5 + n / 5 / 5 / 5 + ...
        因此,我们这样进行循环
        n /= 5;
        count += n;
        这样,第一次加上的就是 每隔 5 个数的 5 的个数,第二次加上的就是 每隔 25 个数的 5 的个数 ...
        */
        int count = 0;
        while(n >= 5){
            n /= 5;
            count += n;
        }
        return count;
    }
}

Q16.6 最小差

给定两个整数数组a和b,计算具有最小差绝对值的一对数值(每个数组中取一个值),并返回该对数值的差

示例:

输入:{1, 3, 15, 11, 2}, {23, 127, 235, 19, 8}
输出: 3,即数值对(11, 8)
提示:

1 <= a.length, b.length <= 100000
-2147483648 <= a[i], b[i] <= 2147483647
正确结果在区间[-2147483648, 2147483647]内

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-difference-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int smallestDifference(int[] a, int[] b) {
        /*
        对两个数组进行排序
        双指针
        
        int diff = a[i] - b[j]
        如果 diff < 0 ,表示 a[i] 小于 b[j] ,a 尽可能接近 b,那么 i++
        如果 diff > 0 ,表示 a[i] 大于 b[j] ,b 尽可能接近 a,那么 j++

        特殊情况:
        a = {1,2,3,4,5}
        b = {6,7,8,9,10}
        如果 a 数组最大值比 b 数组最小值还小,那么 a 数组 i 会一直右移,直到到达边界 break
        */
        int alen = a.length;
        int blen = b.length;

        Arrays.sort(a);
        Arrays.sort(b);
        int minVal = Integer.MAX_VALUE;

        int i = 0;
        int j = 0;
        while(i < alen && j < blen){
            //使用 long,防止 -2147483648 转正数后还是 -2147483648
            long diff = a[i] - b[j];
            minVal = (int)Math.min(Math.abs(diff), minVal);
            if(diff < 0){
                i++;
            }else{
                j++;
            }
        }
        return minVal;
    }
}

Q16.7 最大数值

编写一个方法,找出两个数字ab中最大的那一个。不得使用if-else或其他比较运算符。

示例:

输入: a = 1, b = 2
输出: 2
class Solution {
    public int maximum(int a, int b) {
        long dif = (long)a - (long)b;
        int k = (int)(dif >>> 63);
        return a*(k^1) + b*k;
    }
}

Q16.8 整数的英语表示

给定一个整数,打印该整数的英文描述。

示例 1:

输入: 123
输出: "One Hundred Twenty Three"
示例 2:

输入: 12345
输出: "Twelve Thousand Three Hundred Forty Five"
示例 3:

输入: 1234567
输出: "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"
示例 4:

输入: 1234567891
输出: "One Billion Two Hundred Thirty Four Million Five Hundred Sixty Seven Thousand Eight Hundred Ninety One"

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/english-int-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

/*
 *@v7fgg
 *执行用时 :17 ms, 在所有 Java 提交中击败了27.86%的用户
 *内存消耗 :39.8 MB, 在所有 Java 提交中击败了100.00%的户
 *2020年6月18日 22:24
 */
class Solution {
    public String numberToWords(int num) {
        //考虑特殊情况的0
        if(num==0){return "Zero";}
        String ans="";
        //原数字在后面还要用到,因此复制一份,这里只需要考虑绝对值
        int m=Math.abs(num);
        int yi=m%1000;//1000以内的值,也就是后三位
        int qian=m/1000%1000;//多少千thousand
        int baiwan=m/1000000%1000;//多少百万million
        int shiyi=m/1000000000;//多少十亿billion
        if(yi>0){
            ans=in1000(yi);
        }
        if(qian>0){
            ans=in1000(qian)+" Thousand "+ans;
        }
        if(baiwan>0){
            ans=in1000(baiwan)+" Million "+ans;
        }
        if(shiyi>0){
            ans=in1000(shiyi)+" Billion "+ans;
        }
        //考虑负数的情况
        if(num<0){ans="Negative "+ans;}
        return ans.trim();
    }
    public String in1000(int a){
        //此函数是把一个1000以内的数字变成字符串
        String shuzi1[]=new String[]{"","One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten","Eleven","Twelve","Thirteen","Fourteen","Fifteen","Sixteen","Seventeen","Eighteen","Nineteen"};
        String shuzi2[]=new String[]{"","Ten","Twenty","Thirty","Forty","Fifty","Sixty","Seventy","Eighty","Ninety"};
        String r="";
        if(a%100<20){
            r=shuzi1[a%100];
            a/=100;
        }
        else{
            r=shuzi1[a%10];
            a/=10;
            if(a>0){
                //要去掉空格,因为会出现比如:3000000 thirty thousand
                r=(shuzi2[a%10]+" "+r).trim();
                a/=10;
            }
        }
        if(a>0){
            //去空格是因为会出现比如:100000 one hundred thousand
            r=(shuzi1[a]+" Hundred "+r).trim();
        }
        return r;
    }
}

Q16.9 运算

请实现整数数字的乘法、减法和除法运算,运算结果均为整数数字,程序中只允许使用加法运算符和逻辑运算符,允许程序中出现正负常数,不允许使用位运算。

你的实现应该支持如下操作:

Operations() 构造函数
minus(a, b) 减法,返回a - b
multiply(a, b) 乘法,返回a * b
divide(a, b) 除法,返回a / b
示例:

Operations operations = new Operations();
operations.minus(1, 2); //返回-1
operations.multiply(3, 4); //返回12
operations.divide(5, -2); //返回-2
提示:

你可以假设函数输入一定是有效的,例如不会出现除法分母为0的情况
单个用例的函数调用次数不会超过1000次

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/operations-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

import java.math.BigInteger;
class Operations {

    public Operations() {

    }
    
    public int minus(int a, int b) {
        return BigInteger.valueOf(a).subtract(BigInteger.valueOf(b)).intValue();
    }
    
    public int multiply(int a, int b) {
        return BigInteger.valueOf(a).multiply(BigInteger.valueOf(b)).intValue();
    }
    
    public int divide(int a, int b) {
        return BigInteger.valueOf(a).divide(BigInteger.valueOf(b)).intValue();
    }
}

Q16.10 生存人数

给定 N 个人的出生年份和死亡年份,第 i 个人的出生年份为 birth[i],死亡年份为 death[i],实现一个方法以计算生存人数最多的年份。

你可以假设所有人都出生于 1900 年至 2000 年(含 1900 和 2000 )之间。如果一个人在某一年的任意时期处于生存状态,那么他应该被纳入那一年的统计中。例如,生于 1908 年、死于 1909 年的人应当被列入 1908 年和 1909 年的计数。

如果有多个年份生存人数相同且均为最大值,输出其中最小的年份。

 

示例:

输入:
birth = {1900, 1901, 1950}
death = {1948, 1951, 2000}
输出: 1901
 

提示:

0 < birth.length == death.length <= 10000
birth[i] <= death[i]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/living-people-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
    public int maxAliveYear(int[] birth, int[] death) {
        int[] count = new int[102];
        for (int j = 0; j < birth.length; j++) {
            count[birth[j] - 1900] += 1;
            count[death[j] - 1899] -= 1;
        }
        int maxIndex = 0;
        int maxCount = -1;
        for (int i = 1; i < 102; i++) {
            count[i] = count[i] + count[i - 1];
            if (count[i] > maxCount) {
                maxCount = count[i];
                maxIndex = i;
            }
        }
        return maxIndex + 1900;
    }
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值