LeetCode:数学运算,奇怪数字,等差数列,规律数列,函数曲线

1,数学运算

50,Pow(x, n)

题目:实现 pow(x,n) ,即计算 x 的整数 n 次幂函数(即,x^n )。

思路:使用折半计算,每次把n缩小一半,这样n最终会缩小到0,任何数的0次方都为1,这时候我们再往回乘,如果此时n是偶数,直接把上次递归得到的值算个平方返回即可,如果是奇数,则还需要乘上个x的值。还有一点需要引起我们的注意的是n有可能为负数,对于n是负数的情况,我们可以先用其绝对值计算出一个结果再取其倒数即可。我们让i初始化为n,然后看i是否是2的倍数,是的话x乘以自己,否则res乘以x,i每次循环缩小一半,直到为0停止循环。最后看n的正负,如果为负,返回其倒数。

class Solution {
    public double myPow(double x, int n) {
        double res = 1.0;
        for(int i = n; i != 0; i /= 2){
            if(i % 2 != 0){
                res *= x;
            }
            x *= x;
        }
        return  n < 0 ? 1 / res : res;
    }
} 

69,x的平方根

题目:给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

class Solution {
    public int mySqrt(int num) {
        int left = 1;
        int right = num;
        int middle = 0;
        while (left <= right) {
            middle = left + (right - left) / 2;
            int temp = num / middle;
            if (temp > middle) {
                left = middle + 1;
            } else if (temp < middle) {
                right = middle - 1;
            } else if (temp == middle) {
                return middle;
            }
        }
        return right;
    }
}

279,完全平方数

题目:给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,149 和 16 都是完全平方数,而 3 和 11 不是。

思路:判断完全平方数+背包问题

class Solution {
   public int numSquares(int n) {
        ArrayList arrayList = new ArrayList();
        for (int i = 1; i <= n; i++) {
            if (isPerfectSquare(i)) {
                arrayList.add(i);
            }
        }
        Integer[] a = (Integer[]) arrayList.toArray(new Integer[arrayList.size()]);
        return coinChange(a, n);
    }
    public boolean isPerfectSquare(int num) {
        if (num == 1) {
            return true;
        }
        if (num == 2) {
            return false;
        }
        int left = 1;
        int right = num;
        while (left <= right) {
            int middle = left + (right - left) / 2;
            int temp = num / middle;
            if (temp > middle) {
                left = middle + 1;

            } else if (temp < middle) {
                right = middle - 1;
            } else if (temp == middle) {
                if (num % middle == 0) return true;
                left = middle + 1;
            }
        }
        return false;
    }
    public int coinChange(Integer[] coins, int amount) {
        int max = amount + 1;
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, max);
        dp[0] = 0;
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

367,有效的完全平方数

题目:给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

思路:加法防溢出,乘法防溢出。

class Solution {
    public boolean isPerfectSquare(int num) {
        if (num==1){
            return true;
        }
        if (num==2){
            return false;
        }
        int left = 1;
        int right = num;
         while (left <= right) {
            int middle = left+(right-left)/2;
            int temp = num/middle;
            if (temp > middle) {
                left=middle+1;

            }else if (temp<middle){
                right=middle-1;
            }else if (temp==middle){
                if (num%middle == 0) return true;
                left = middle + 1;
            }
        }
        return false;
    }
}

399,除法求值

题目:给你一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。

返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。

注意:输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

class Solution {
    public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
        int cnt=0;
        //哈希预处理
        HashMap<String,Integer> map=new HashMap<>();
        int n=equations.size();
        for(int i=0;i<n;i++){
            for(int j=0;j<2;j++){
                if(!map.containsKey(equations.get(i).get(0)))
                    map.put(equations.get(i).get(0),cnt++);
                if(!map.containsKey(equations.get(i).get(1)))
                    map.put(equations.get(i).get(1),cnt++);
            }
        }

        //建图预处理
        double [][] graph=new double [cnt][cnt];
        for(int i=0;i<cnt;i++){
            Arrays.fill(graph[i],-1.0);
        }

        //建图,乘积
        for(int i=0;i<n;i++){
            int va=map.get(equations.get(i).get(0));
            int vb=map.get(equations.get(i).get(1));
            graph[va][vb]=values[i];
            graph[vb][va]=1.0/values[i];
        }

        //Floyd算法
        for(int k=0;k<cnt;k++){
            for(int i=0;i<cnt;i++){
                for(int j=0;j<cnt;j++){
                    if(graph[i][k]>0&&graph[k][j]>0)
                        graph[i][j]=graph[i][k]*graph[k][j];
                }
            }
        }

        //获取结果
        int m=queries.size();
        double [] res=new double [m];
        for(int i=0;i<m;i++){
            List<String> query=queries.get(i);
            double tmp=-1.0;
            if(map.containsKey(query.get(0))&&map.containsKey(query.get(1))){
                int va=map.get(query.get(0));
                int vb=map.get(query.get(1));
                if(graph[va][vb]>0) tmp=graph[va][vb];
            }
            res[i]=tmp;
        }
        return res;
    }
}

989,数组形式的整数加法

题目:整数的 数组形式  num 是按照从左到右的顺序表示其数字的数组。例如,对于 num = 1321 ,数组形式是 [1,3,2,1] 。给定 num ,整数的 数组形式 ,和整数 k ,返回 整数 num + k 的 数组形式 。

class Solution {
    public List<Integer> addToArrayForm(int[] num, int k) {
        int kk = k;
        ArrayList arrayList = new ArrayList();
        int i = num.length - 1;
        boolean flag = false;
        while (k != 0 && i != -1) {
            int temp = k % 10;
            k /= 10;
            int a = temp + num[i];
            if (flag) {
                a++;
            }
            if (a >= 10) {
                a -= 10;
                flag = true;
            } else {
                flag = false;
            }
            arrayList.add(a);
            i--;
        }
        if (num.length > (kk + "").length()) {
            for (; i >= 0; i--) {
                int a = num[i];
                if (flag) {
                    a++;
                }
                if (a >= 10) {
                    a -= 10;
                    flag = true;
                } else {
                    flag = false;
                }
                arrayList.add(a);
            }
        } else if (num.length < (kk + "").length()) {
            while (k != 0) {
                int a = k % 10;
                k /= 10;
                if (flag) {
                    a++;
                }
                if (a >= 10) {
                    a -= 10;
                    flag = true;
                } else {
                    flag = false;
                }
                arrayList.add(a);
            }
        }
        if (flag){
                arrayList.add(1);
            }
        Collections.reverse(arrayList);
        return arrayList;
    }
}

1281,整数的各位积和之差

题目:给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。

class Solution {
    public int subtractProductAndSum(int n) {
        int muti = 1;
        int sum = 0;
        while(n!=0){
        	muti *=n%10;
        	sum +=n%10;
        	n/=10;
        } 
        return muti-sum;
    }
}

1822,数组元素积的符号

题目:已知函数 signFunc(x) 将会根据 x 的正负返回特定值:

  • 如果 x 是正数,返回 1 。
  • 如果 x 是负数,返回 -1 。
  • 如果 x 是等于 0 ,返回 0 。

给你一个整数数组 nums 。令 product 为数组 nums 中所有元素值的乘积。

思路:统计正数个数,负数个数,决不能乘积完判断大小,溢出。

class Solution {
    public int arraySign(int[] nums) {
        int result = 1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i]==0){
                return 0;
            }else if (nums[i]>0){
                result*=1;
            }else if (nums[i]<0){
                result*=-1;
            }
        }
        return result;
    }
}

2,奇怪数字

92,3,5,7乘积组合

题目:有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

class Solution {
    public int getKthMagicNumber(int k) {
        int[] dp = new int[k + 1];
        dp[1] = 1;
        int p3 = 1, p5 = 1, p7 = 1;
        for (int i = 2; i <= k; i++) {
            int num3 = dp[p3] * 3, num5 = dp[p5] * 5, num7 = dp[p7] * 7;
            dp[i] = Math.min(Math.min(num3, num5), num7);
            if (dp[i] == num3) {
                p3++;
            }
            if (dp[i] == num5) {
                p5++;
            }
            if (dp[i] == num7) {
                p7++;
            }
        }
        return dp[k];
    }
}

202,快乐数

题目:编写一个算法来判断一个数 n 是不是快乐数。如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。
class Solution {
    public boolean isHappy(int n) {
         for (int i = 0; i < 30; i++) {
            int temp = 0;
            while (n > 0) {
                temp += (n % 10) * (n % 10);
                n /= 10;
            }
            if (temp == 1) {
                return true;
            } else {
                n = temp;
            }
        }
        return false;
    }
}

264,丑数 II

题目:我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。

思路:这个题用三指针,第一个丑数是1,以后的丑数都是基于前面的小丑数分别乘2,3,5构成的。我们每次添加进去一个当前计算出来个三个丑数的最小的一个,并且是谁计算的,谁指针就后移一位。

public class NthUglyNumber {
    public int nthUglyNumber(int n) {
        if (n <= 0) return -1;
        int[] dp = new int[n];
        dp[0] = 1;
        int id2 = 0, id3 = 0, id5 = 0;
        for (int i = 1; i < n; i++) {
            dp[i] = Math.min(dp[id2] * 2, Math.min(dp[id3] * 3, dp[id5] * 5));
            // 这里不用else if的原因是有可能id2(3) * 2 == id3(2) * 3
            // 这种情况两个指针都要后移
            if (dp[id2] * 2 == dp[i]) id2 += 1;
            if (dp[id3] * 3 == dp[i]) id3 += 1;
            if (dp[id5] * 5 == dp[i]) id5 += 1;
        }
        return dp[n - 1];
    }
}

274,H指数

题目:给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。

根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且每篇论文 至少 被引用 h 次。如果 h 有多种可能的值,h 指数 是其中最大的那个。

class Solution {
    public int hIndex(int[] citations) {
        Arrays.sort(citations);
        if (citations.length == 1) {
            return citations[0] >= 1 ? 1 : 0;
        }
        int left = 0;
        int right = citations.length;
        int middle = 0;
        int ans = 0;
        while (left < right) {
            middle = left + (right - left) / 2;
            int temp = citations.length - middle;
            if (temp > citations[middle]) {
                left = middle + 1;
            } else {
                right = middle;
            }
        }
        return citations.length - left;
    }
}

275,H指数 II

题目:给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数,citations 已经按照 升序排列 。计算并返回该研究者的 h 指数。

h 指数的定义:h 代表“高引用次数”(high citations),一名科研人员的 h 指数是指他(她)的 (n 篇论文中)总共有 h 篇论文分别被引用了至少 h 次。且其余的 n - h 篇论文每篇被引用次数 不超过 h 次。

提示:如果 h 有多种可能的值,h 指数 是其中最大的那个。请你设计并实现对数时间复杂度的算法解决此问题。

class Solution {
    public int hIndex(int[] citations) {
        if (citations.length == 1) {
            return citations[0] >= 1 ? 1 : 0;
        }
        int left = 0;
        int right = citations.length;
        int middle = 0;
        int ans = 0;
        while (left < right) {
            middle = left + (right - left) / 2;
            int temp = citations.length - middle;
            if (temp > citations[middle]) {
                left = middle + 1;
            } else {
                right = middle;
            }
        }
        return citations.length-left;
    }
}

1201,丑数 III

题目:给你四个整数:n 、a 、b 、c ,请你设计一个算法来找出第 n 个丑数。丑数是可以被 a  b  c 整除的 正整数 。

思路:一个区间的可以被a/b/c除的个数为 num/a+num/b+num/c-num/(ab)- num(bc)-num(ac)+num(abc) 

class Solution {
    public int nthUglyNumber(int n, int a, int b, int c) {
        long ab = zuixiaogongbei(a, b);
        long bc = zuixiaogongbei(b, c);
        long ac = zuixiaogongbei(a, c);
        long abc = zuixiaogongbei(a, bc);
        long min = Math.min(a, Math.min(b, c));
        long l = 0;
        long r = min * n;
        while (l <= r) {
            long mid = (l + r) >> 1;
            long cnt = mid / a + mid / b + mid / c - mid / ab - mid / bc - mid / ac + mid / abc;
            if (cnt == n) {
                if (mid % a == 0 || mid % b == 0 || mid % c == 0)
                    return (int) mid;
                else
                    r = mid - 1;
            } else if (cnt > n)
                r = mid - 1;
            else
                l = mid + 1;
        }
        return (int) l;
    }

    public long zuixiaogongbei(long a, long b) {
        return (b / gcd(a, b)) * a;
    }

    public int gcd(long x, long y) {
        return y == 0 ? (int) x : gcd(y, x % y);
    }
}

3,等差数列

413,等差数列划分

题目:如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。子数组 是数组中的一个连续序列。

class Solution {
    public int numberOfArithmeticSlices(int[] nums) {
        int n = nums.length;
        if (n == 1) {
            return 0;
        }

        int d = nums[0] - nums[1], t = 0;
        int ans = 0;
        // 因为等差数列的长度至少为 3,所以可以从 i=2 开始枚举
        for (int i = 2; i < n; ++i) {
            if (nums[i - 1] - nums[i] == d) {
                ++t;
            } else {
                d = nums[i - 1] - nums[i];
                t = 0;
            }
            ans += t;
        }
        return ans;
    }
}

441,排列硬币

题目:你总共有 n 枚硬币,并计划将它们按阶梯状排列。对于一个由 k 行组成的阶梯,其第 i 行必须正好有 i 枚硬币。阶梯的最后一行 可能 是不完整的。给你一个数字 n ,计算并返回可形成 完整阶梯行 的总行数。

思路:

S_n\geqslant n*a_1+\frac{n(n-1)}{2}*d

S_n\geqslant n*1+\frac{n(n-1)}{2}*1

S_n\geqslant n+\frac{n(n-1)}{2}=\frac{n(n+1)}{2}=\frac{n^2+n}{2}

2S_n\geqslant n^2+n

2S_n+\frac{1}{4}\geqslant n^2+n+\frac{1}{4}=(n+\frac{1}{2})^2

\sqrt{2S_n+\frac{1}{4}}\geqslant n+\frac{1}{2}

n\leqslant \sqrt{2S_n+\frac{1}{4}}-\frac{1}{2}

class Solution {
    public int arrangeCoins(int n) {
        return (int) (Math.sqrt(2 * (long) n + 0.25)-0.5);
    }
}

1502,判断能否形成等差数列

题目:给你一个数字数组 arr 。如果一个数列中,任意相邻两项的差总等于同一个常数,那么这个数列就称为 等差数列 。如果可以重新排列数组形成等差数列,请返回 true ;否则,返回 false 。

class Solution {
    public boolean canMakeArithmeticProgression(int[] arr) {
        Arrays.sort(arr);
        int temp = arr[1]-arr[0];
        for (int i = 1; i < arr.length-1; i++) {
            if (arr[i+1]-arr[i]!=temp){
                return false;
            }
        }
        return true;
    }
}

1630,等差子数列

题目:给你一个由 n 个整数组成的数组 nums,和两个由 m 个整数组成的数组 l 和 r,后两个数组表示 m 组范围查询,其中第 i 个查询对应范围 [l[i], r[i]] 。所有数组的下标都是 从 0 开始 的。返回 boolean 元素构成的答案列表 answer 。如果子数组 nums[l[i]], nums[l[i]+1], ... , nums[r[i]] 可以 重新排列 形成 等差数列 ,answer[i] 的值就是 true;否则answer[i] 的值就是 false 。

class Solution {
    public List<Boolean> checkArithmeticSubarrays(int[] nums, int[] l, int[] r) {
        ArrayList result = new ArrayList();
        int m = l.length;
        for (int i = 0; i < m; i++) {
            int left = l[i];
            int right = r[i];
            int[] temp = new int[right - left + 1];
            for (int j = left; j <= right; j++) {
                temp[j - left] = nums[j];
            }
            Arrays.sort(temp);
            result.add(canMakeArithmeticProgression(temp));
        }
        return result;
    }

    public boolean canMakeArithmeticProgression(int[] arr) {
        Arrays.sort(arr);
        int temp = arr[1] - arr[0];
        for (int i = 1; i < arr.length - 1; i++) {
            if (arr[i + 1] - arr[i] != temp) {
                return false;
            }
        }
        return true;
    }
}

4,规律数列

233,数字1,2的个数

题目:给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。

class Solution {
    public int countDigitOne(int n) {
        long ans = 0;
        long count;
        long rest;
        for (long i = 1; i <= n; i *= 10) {
            count = (n / (i * 10)) * i; // 分别统计个位的1  十位  百位.....
            //111   个位共计11个1,  '1', 1'1', 2'1', 3'1', 4'1', 5'1', 6'1', 7'1', 8'1', 9'1', 10'1'
            //只统计到小于等于110 多出为余数
            //111  十位有10个1, '1'0, '1'1, '1'2, '1'3, '1'4, '1'5, '1'6, '1'7, '1'8, '1'9
            rest = Math.min(Math.max(n % (i * 10) - (i - 1), 0), i);  // 1  0   // 10  9  //100 99
            //下面举例100和111的余数
            // 如果为负数则取余为0
            // 100  个位为0 无余数
            // 111  个位为1 有一个余数    111  第三位   11‘1’
            // 100  十位为0 无余数
            // 111  十位为1 有两个余数    110  111  中间位置1‘1’0 和1‘1’1
            // 100  百位为1 有一个余数    100  第一位‘1’00
            // 111  百位为1 有十二个余数  100....... 111  第一位 '1'00 ..........  '1'11
            ans += (count + rest);
        }
        return (int)ans;
    }
}

题目:编写一个方法,计算从 0 到 n (含 n) 中数字 2 出现的次数。

思路:

  • 当某一位小于2时,该位上数字2出现的次数等于高位数字乘以当前位的权重(比如说,对于个位来说,权重是1;对于十位来说,权重是10)。
  • 当某一位等于2时,该位上数字2出现的次数等于高位数字乘以当前位的权重,再加上低位数字加1。
  • 当某一位大于2时,该位上数字2出现的次数等于(高位数字加1)乘以当前位的权重。
class Solution {
    public int numberOf2sInRange(int n) {
         int count = 0;
    int weight = 1;
    
    while (n >= weight) {
        int high = n / (weight * 10);
        int current = (n / weight) % 10;
        int low = n % weight;

        if (current < 2) {
            count += high * weight;
        } else if (current == 2) {
            count += high * weight + low + 1;
        } else {
            count += (high + 1) * weight;
        }

        weight *= 10;
    }
    
    return count;
    }
}

400,第N位数字

题目:给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] 中找出并返回第 n 位上的数字。

/* 数字范围    数量  位数    占多少位
    1-9        9      1       9
    10-99      90     2       180
    100-999    900    3       2700
    1000-9999  9000   4       36000  ...

    例如 2901 = 9 + 180 + 2700 + 12 即一定是4位数,第12位   n = 12;
    数据为 = 1000 + (12 - 1)/ 4  = 1000 + 2 = 1002
    定位1002中的位置 = (n - 1) %  4 = 3    s.charAt(3) = 2;
*/
class Solution {
    public int findNthDigit(int n) {
        int digit = 1;   // n所在数字的位数
        long start = 1;  // 数字范围开始的第一个数
        long count = 9;  // 占多少位
        while(n > count){
            n -= count;
            digit++;
            start *= 10;
            count = digit * start * 9;
        }
        long num = start + (n - 1) / digit;
        return Long.toString(num).charAt((n - 1) % digit) - '0';
    }
}

5,函数曲线

64,交点

题目:给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。

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);
    }
}

73,平方正方形

题目:给定两个正方形及一个二维平面。请找出将这两个正方形分割成两半的一条直线。假设正方形顶边和底边与 x 轴平行。

每个正方形的数据square包含3个数值,正方形的左下顶点坐标[X,Y] = [square[0],square[1]],以及正方形的边长square[2]。所求直线穿过两个正方形会形成4个交点,请返回4个交点形成线段的两端点坐标(两个端点即为4个交点中距离最远的2个点,这2个点所连成的线段一定会穿过另外2个交点)。2个端点坐标[X1,Y1][X2,Y2]的返回格式为{X1,Y1,X2,Y2},要求若X1 != X2,需保证X1 < X2,否则需保证Y1 <= Y2

若同时有多条直线满足要求,则选择斜率最大的一条计算并返回(与Y轴平行的直线视为斜率无穷大)。

class Solution {
    public double[] cutSquares(int[] square1, int[] square2) {
        double x1 = square1[0] + square1[2] / 2.0;
        double y1 = square1[1] + square1[2] / 2.0;

        double x2 = square2[0] + square2[2] / 2.0;
        double y2 = square2[1] + square2[2] / 2.0;

        if (x1 == x2) {
            double temp1 = square1[1] + square1[2];
            double temp2 = square2[1] + square2[2];
            return new double[]{x1, Math.min(square1[1], square2[1]), x1, Math.max(temp2, temp1)};
        }
        double[] result = new double[4];
        double k = (y2 - y1) / (x2 - x1);
        double b = y2 - k * x2;

        if(Math.abs(k) >= 1){ // 直线穿过两个正方形的上下边
            result[1] = Math.min(square1[1], square2[1]);  // 先求出y,选两个正方形中靠下的底边
            result[0] = (result[1]-b)/k;
            result[3] = Math.max(square1[1]+square1[2], square2[1]+square2[2]);
            result[2] = (result[3]-b)/k;
        }else{
            result[0] = Math.min(square1[0], square2[0]);
            result[1] = k*result[0]+b;
            result[2] = Math.max(square1[0]+square1[2], square2[0]+square2[2]);
            result[3] = k*result[2]+b;
        }
        if(result[0] > result[2]){
            swap(result, 0, 2);
            swap(result, 1, 3);
        }
        return result;
    }
    public void swap(double[] res, int x, int y){
        double temp = res[x];
        res[x] = res[y];
        res[y] = temp;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕双嘤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值