算法题解之math类题

Bulb Switcher

灯泡开关

思路:除了平方数以外,其他所有位置的灯泡最终都被开关了偶数次,因此最终都为0。问题等价于求1~n中平方数的个数。

1 public class Solution {
2     public int bulbSwitch(int n) {
3         return (int)Math.sqrt(n);
4     }
5 }
View Code

 

Count Primes

质数计数

思路1:暴力法。其中判断每一个数n是不是质数需要验证是否任何小于n的数都不能整除n,这一步是O(n)。因此整体复杂度是O(n^2)。

思路2:思路1的优化版。如果一个数n不是质数,则n = p * q。令 p <= q,则可以推出 p * p <= n,即 p <= √n。因此思路一中只需要判断是否任何小于等于√n都不能整除n。整体时间复杂度变为O(n^1.5)。

 1 public int countPrimes(int n) {
 2    int count = 0;
 3    for (int i = 1; i < n; i++) {
 4       if (isPrime(i)) count++;
 5    }
 6    return count;
 7 }
 8 
 9 private boolean isPrime(int num) {
10    if (num <= 1) return false;
11    // Loop's ending condition is i * i <= num instead of i <= sqrt(num)
12    // to avoid repeatedly calling an expensive function sqrt().
13    for (int i = 2; i * i <= num; i++) {
14       if (num % i == 0) return false;
15    }
16    return true;
17 }
View Code

思路3:埃拉托色尼筛选法:对于当前数i(i要从2开始),把它的倍数2i,3i,4i......都标记为不是质数,然后 i 的下一个没有被标记过的数一定是质数。

优化:(1)如果一个数已经被标记为不是质数了,直接跳过,因为它的倍数之前一定已经标记过了;(2)对于数i,不用从2i开始标记,直接从i * i开始标记(之前的也一定被标记过)。

算法空间复杂度为O(n),时间复杂度为O(n log log n)。(证明见wiki)

 1 public class Solution {
 2     public int countPrimes(int n) {
 3         boolean[] notPrime = new boolean[n];
 4         int count = 0;
 5         for (int i = 2; i < n; i++) {
 6             if (notPrime[i] == false) {
 7                 count++;
 8                 for (long j = i; i * j < n; j++) {
 9                     notPrime[(int)(i * j)] = true;
10                 }
11             }
12         }
13         
14         return count;
15     }
16 }
View Code

Insert Interval

插入区间

思路:区间类题目。先把区间按照start大小插入进去,然后就就跟排好序的merge intervals一样了。

 1 /**
 2  * Definition for an interval.
 3  * public class Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() { start = 0; end = 0; }
 7  *     Interval(int s, int e) { start = s; end = e; }
 8  * }
 9  */
10 public class Solution {
11     public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
12         List<Interval> res = new ArrayList<Interval>();
13         if (intervals == null || intervals.size() == 0) {
14             res.add(newInterval);
15             return res;
16         }
17         
18         for (int i = 0; i < intervals.size(); i++) {
19             if (intervals.get(i).start > newInterval.start) {
20                 intervals.add(i, newInterval);
21                 break;
22             } else if (i == intervals.size() - 1) {
23                 intervals.add(newInterval);
24                 break;
25             }
26         }
27         
28         res.add(intervals.get(0));
29         for (int i = 1; i < intervals.size(); i++) {
30             Interval cur = intervals.get(i);
31             Interval last = res.get(res.size() - 1);
32             if (cur.start <= last.end) {
33                 last.end = Math.max(last.end, cur.end);
34             } else {
35                 res.add(cur);
36             }
37         }
38         return res;
39         
40     }
41 }
View Code

Merge Intervals

合并区间

思路:区间类题目。先把所有区间按照start排好序,把第一个区间加到合并集中。然后遍历之后的每个区间,只需要与合并集中最后一个区间进行比较合并。

 1 /**
 2  * Definition for an interval.
 3  * public class Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() { start = 0; end = 0; }
 7  *     Interval(int s, int e) { start = s; end = e; }
 8  * }
 9  */
10 public class Solution {
11     public List<Interval> merge(List<Interval> intervals) {
12         
13         List<Interval> res = new ArrayList<Interval>();
14 
15         if (intervals == null || intervals.size() == 0) {
16             return res;
17         }
18         
19         Comparator<Interval> c = new Comparator<Interval>() {
20             public int compare(Interval i1, Interval i2) {
21                 return i1.start - i2.start;
22             }
23         };
24         Collections.sort(intervals, c);
25         res.add(intervals.get(0));
26         for (int i = 1; i < intervals.size(); i++) {
27             Interval cur = intervals.get(i);
28             Interval last = res.get(res.size() - 1);
29             if (cur.start <= last.end) {
30                 last.end = Math.max(last.end, cur.end);
31             } else {
32                 res.add(cur);
33             }
34         }
35         return res;
36     }
37 }
View Code

Power of Three

判断3的次方

思路1:循环或者递归。复杂度O(lgn)

思路2:题目规定不能用loop或者递归。可以调用java的log函数来做。时间仍然是O(lgn)

思路3:求出int中3的次方的最大值,判断max是否能被n整除。时间是O(1)。power of tow,power of four 均与这题类似。

public class Solution {
    public boolean isPowerOfThree(int n) {
        int Max3PowerInt = 1162261467;
        if (n > 0 && n <= Max3PowerInt) {
            if (Max3PowerInt % n == 0) {
                return true;
            }
        }
        return false;
    }
}
View Code

Rectangle Area

矩形面积

思路:设矩形1的上下左右边分别为u1,d1,l1,r1,矩形2的上下左右边分别为u2,d2,l2,r2。则两矩形不相交的充要条件是:u1在d2下方 或 u2在d1下方 或 l1在r2右边 或 l2在r1右边。其余情况一定相交。相交面积的求法是:相交矩形的左边是l1和l2其中靠右的边,相交矩形的右边是r1和r2其中靠左的边,相交矩形的上边是u1和u2的靠下的边,相交矩形的下边是d1和d2的靠上的边。

 1 public class Solution {
 2     public int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
 3         int area1 = (C - A) * (D - B);
 4         int area2 = (G - E) * (H - F);
 5         if (A >= G || E >= C || B >= H || F >= D) {
 6             return area1 + area2;
 7         }
 8         
 9         int w = Math.min(C, G) - Math.max(A, E);
10         int h = Math.min(D, H) - Math.max(B, F);
11         return area1 + area2 - w * h;
12         
13     }
14 }
View Code
原文地址:https://www.cnblogs.com/coldyan/p/6058625.html