校招算法笔面试 | 校招笔面试真题-交叉线

题目## 题目

题目链接

题解:

考察点: 思维,数形结合,暴力

易错点:

1. 1. 1.本题中要求的是相交的半圆,如果存在两个半圆,直径分别为 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] [ l 2 , r 2 ] [l_2,r_2] [l2,r2],并且满足 l 1 ≤ l 2 , r 2 ≤ r 1 l_1 \leq l_2,r_2 \leq r_1 l1l2r2r1,则不属于相交的情况,所以如果按照结束位置排序的方法来贪心并不可行

2. 2. 2.一定注意题目中明确说明在端点处相交不算相交

解法:

这题通过数形结合的方法更容易理解,设两个半圆的端点分别为 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] [ l 2 , r 2 ] [l_2,r_2] [l2,r2],则相交时有如下图所示的情况:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在有了上述结论后,题目就变得简单,直接对于半圆 i i i,直接枚举其前面位置的半圆,看和其是否存在交点,复杂度为 O ( n 2 ) O(n^2) O(n2)

#include "bits/stdc++.h"
using namespace std;
const int maxn=1e3+10;
int T,n;
int a[maxn];
struct node{
    int l,r;
}p[maxn];
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(a,0,sizeof(a));
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=2;i<=n;i++){
            p[i-1].l=min(a[i-1],a[i]);
            p[i-1].r=max(a[i-1],a[i]);
        }
        --n;
        int flag=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<i;j++){ if((p[j].l<p[i].r&&p[j].l>p[i].l&amp;&amp;p[j].r&gt;p[i].r)||(p[j].r<p[i].r&&p[j].r>p[i].l&amp;&amp;p[j].l</p[i].r&&p[j].r></i;j++){>

[题目链接](https://www.nowcoder.com/practice/43d22dbc8bef46529e722dc6a5fb1e2d?tpId=182&tqId=354364&sourceUrl=/exam/oj&channelPut=wcsdn&fromPut=wcsdn)

## 解题思路

计算32位整数二进制表示中1的个数,有几种常用方法:

1. **位运算法**- 使用 $\text{n} \& \text{1}$ 判断最低位是否为1
   - 右移 $\text{n}$,继续判断
   - 统计所有为1的位

2. **n & (n-1)**- 每次操作会消除最右边的1
   - 统计操作次数即为1的个数
   - 这种方法更高效,因为只需要处理1的个数次

3. **查表法**- 预处理所有8位数的1的个数
   -32位数分成48位处理
   - 适合处理大量数据

---

## 代码

```c++
#include <iostream>
using namespace std;

class Solution {
public:
    // 方法1:位运算统计
    int countOnes1(int n) {
        int count = 0;
        while (n) {
            count += n & 1;
            n >>= 1;
        }
        return count;
    }
    
    // 方法2:n & (n-1)
    int countOnes2(int n) {
        int count = 0;
        while (n) {
            n &= (n - 1);
            count++;
        }
        return count;
    }
};

int main() {
    int n;
    cin >> n;
    
    Solution solution;
    cout << solution.countOnes2(n) << endl;
    return 0;
}
import java.util.*;

public class Main {
    static class Solution {
        // 方法1:位运算统计
        public int countOnes1(int n) {
            int count = 0;
            while (n != 0) {
                count += n & 1;
                n >>>= 1;  // 使用无符号右移
            }
            return count;
        }
        
        // 方法2:n & (n-1)
        public int countOnes2(int n) {
            int count = 0;
            while (n != 0) {
                n &= (n - 1);
                count++;
            }
            return count;
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        Solution solution = new Solution();
        System.out.println(solution.countOnes2(n));
    }
}
def count_ones_1(n: int) -> int:
    """方法1:位运算统计"""
    count = 0
    while n:
        count += n & 1
        n >>= 1
    return count

def count_ones_2(n: int) -> int:
    """方法2:n & (n-1)"""
    count = 0
    while n:
        n &= (n - 1)
        count += 1
    return count

if __name__ == "__main__":
    n = int(input())
    print(count_ones_2(n))

算法及复杂度

  • 算法:位运算
  • 时间复杂度:
    • 方法1: O ( 32 ) \mathcal{O}(32) O(32) = O ( 1 ) \mathcal{O}(1) O(1)
    • 方法2: O ( k ) \mathcal{O}(k) O(k) k k k 为1的个数
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值