校招算法笔面试 | 华为机试-查找组成一个偶数最接近的两个素数

题目## 题目

题目链接

解题思路

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

  1. 位运算法:

    • 使用 n & 1 n \& 1 n&1 判断最低位是否为1
    • 右移运算 n > > = 1 n >>= 1 n>>=1 检查下一位
    • 循环直到 n n n 变为0
  2. Brian Kernighan算法:

    • 利用 n & ( n − 1 ) n \& (n-1) n&(n1) 可以消除最右边的1
    • 每次操作都会消除一个1,直到 n n n 变为0
    • 操作次数即为1的个数

代码

#include <iostream>
using namespace std;

int countOnes(int n) {
    int count = 0;
    while (n) {
        n = n & (n - 1);  // 消除最右边的1
        count++;
    }
    return count;
}

int main() {
    int n;
    while (cin >> n) {
        cout << countOnes(n) << endl;
    }
    return 0;
}
import java.util.Scanner;

public class Main {
    public static int countOnes(int n) {
        int count = 0;
        while (n != 0) {
            n &= (n - 1);  // 消除最右边的1
            count++;
        }
        return count;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            System.out.println(countOnes(n));
        }
    }
}
def countOnes(n):
    count = 0
    while n:
        n &= (n - 1)  # 消除最右边的1
        count += 1
    return count

while True:
    try:
        n = int(input())
        print(countOnes(n))
    except:
        break

算法及复杂度

  • 算法:Brian Kernighan算法
  • 时间复杂度: O ( k ) \mathcal{O}(k) O(k),其中k是二进制中1的个数
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

这个解法使用了Brian Kernighan算法,比普通的位运算方法更高效,因为它只需要循环1的个数次,而不是整数的位数次。对于输入数据范围 1 ≤ n ≤ 2 31 − 1 1 ≤ n ≤ 2^{31} - 1 1n2311,这个方法都能高效处理。

题目链接

解题思路

  1. 题目要求:

    • 输入一个大于2的偶数
    • 找出差值最小的两个素数,使它们的和等于输入的偶数
    • 输出这两个素数(按从小到大顺序)
  2. 实现思路:

    • 判断一个数是否为素数
    • 从中间值向两边扩散查找
    • 找到第一对符合条件的素数即为所求
  3. 具体步骤:

    • n / 2 n/2 n/2 开始,分别向左右查找
    • 判断找到的数对是否都是素数
    • 如果都是素数且和为 n n n,则找到答案

代码

#include <iostream>
using namespace std;

bool isPrime(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) return false;
    }
    return true;
}

int main() {
    int n;
    while (cin >> n) {
        // 从中间向两边查找
        int mid = n / 2;
        for (int i = 0; i <= mid; i++) {
            if (isPrime(mid - i) && isPrime(mid + i)) {
                cout << mid - i << endl << mid + i << endl;
                break;
            }
        }
    }
    return 0;
}
import java.util.Scanner;

public class Main {
    private static boolean isPrime(int n) {
        if (n < 2) return false;
        for (int i = 2; i * i <= n; i++) {
            if (n % i == 0) return false;
        }
        return true;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            // 从中间向两边查找
            int mid = n / 2;
            for (int i = 0; i <= mid; i++) {
                if (isPrime(mid - i) && isPrime(mid + i)) {
                    System.out.println(mid - i);
                    System.out.println(mid + i);
                    break;
                }
            }
        }
    }
}
def is_prime(n):
    if n < 2:
        return False
    i = 2
    while i * i <= n:
        if n % i == 0:
            return False
        i += 1
    return True

while True:
    try:
        n = int(input())
        # 从中间向两边查找
        mid = n // 2
        for i in range(mid + 1):
            if is_prime(mid - i) and is_prime(mid + i):
                print(mid - i)
                print(mid + i)
                break
    except EOFError:
        break

算法及复杂度

  • 算法:中心扩散法
  • 时间复杂度: O ( n n ) \mathcal{O}(n\sqrt{n}) O(nn ) - 每次判断素数需要 O ( n ) \mathcal{O}(\sqrt{n}) O(n ),最多需要检查 O ( n ) \mathcal{O}(n) O(n)对数
  • 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只使用常数额外空间
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值