校招算法笔面试 | 校招笔面试真题-万万没想到之抓捕孔连顺

题目## 题目

题目链接

解题思路

这是一个滑动窗口解决组合计数问题。通过维护一个窗口来找到所有满足距离要求的建筑物组合。

关键点:

  1. 使用滑动窗口
  2. 计算组合数
  3. 处理大数运算
  4. 结果取模

算法步骤:

  1. 维护窗口左右边界
  2. 根据距离条件调整窗口
  3. 计算当前窗口内的组合数
  4. 累加结果并取模

代码

#include <bits/stdc++.h>
using namespace std;

class BuildingSelector {
private:
    const int MOD = 99997867;
    
    // 计算在范围内选择2个点的组合数
    long long calculateCombinations(int range) {
        if (range < 2) return 0;
        long long n = range;
        return (n * (n - 1)) / 2;
    }
    
public:
    int findValidCombinations(vector<int>& buildings, int maxDistance) {
        long long totalCombinations = 0;
        int leftPtr = 0;
        int n = buildings.size();
        
        // 使用双指针遍历所有可能的组合
        for (int rightPtr = 0; rightPtr < n; rightPtr++) {
            // 当距离超过限制时,移动左指针
            while (leftPtr < rightPtr && 
                   buildings[rightPtr] - buildings[leftPtr] > maxDistance) {
                leftPtr++;
            }
            
            // 计算当前窗口内的有效组合数
            if (rightPtr - leftPtr >= 2) {
                totalCombinations = (totalCombinations + 
                                   calculateCombinations(rightPtr - leftPtr)) % MOD;
            }
        }
        
        return static_cast<int>(totalCombinations);
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int buildingCount, maxDistance;
    cin >> buildingCount >> maxDistance;
    
    vector<int> buildingPositions(buildingCount);
    for (int& pos : buildingPositions) {
        cin >> pos;
    }
    
    BuildingSelector selector;
    cout << selector.findValidCombinations(buildingPositions, maxDistance) << endl;
    
    return 0;
}
import java.util.*;

class BuildingSelector {
    private static final int MODULO = 99997867;
    
    // 计算有效范围内的组合数
    private long getValidCombinations(int range) {
        if (range < 2) return 0;
        long n = range;
        return (n * (n - 1)) / 2;
    }
    
    public int findPossiblePlans(int[] buildings, int maxDist) {
        long totalPlans = 0;
        int windowStart = 0;
        
        for (int windowEnd = 0; windowEnd < buildings.length; windowEnd++) {
            // 调整窗口起始位置
            while (windowStart < windowEnd && 
                   buildings[windowEnd] - buildings[windowStart] > maxDist) {
                windowStart++;
            }
            
            // 计算当前窗口内的可能方案数
            int windowSize = windowEnd - windowStart;
            if (windowSize >= 2) {
                totalPlans = (totalPlans + getValidCombinations(windowSize)) % MODULO;
            }
        }
        
        return (int) totalPlans;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int d = scanner.nextInt();
        
        int[] buildingPositions = new int[n];
        for (int i = 0; i < n; i++) {
            buildingPositions[i] = scanner.nextInt();
        }
        
        BuildingSelector selector = new BuildingSelector();
        System.out.println(selector.findPossiblePlans(buildingPositions, d));
        
        scanner.close();
    }
}
class BuildingSelector:
    def __init__(self):
        self.MODULO = 99997867
    
    def _calculate_combinations(self, window_size: int) -> int:
        """计算窗口内可能的组合数"""
        if window_size < 2:
            return 0
        return (window_size * (window_size - 1)) // 2
    
    def find_valid_plans(self, buildings: list, max_distance: int) -> int:
        """查找所有有效的埋伏方案数"""
        total_plans = 0
        left = 0
        n = len(buildings)
        
        # 使用滑动窗口查找有效组合
        for right in range(n):
            # 调整窗口左边界,确保最大距离不超过限制
            while left < right and buildings[right] - buildings[left] > max_distance:
                left += 1
            
            # 计算当前窗口内的有效方案数
            window_size = right - left
            if window_size >= 2:
                total_plans = (total_plans + self._calculate_combinations(window_size)) % self.MODULO
        
        return total_plans

def main():
    # 读取输入
    n, d = map(int, input().split())
    building_positions = list(map(int, input().split()))
    
    # 计算结果
    selector = BuildingSelector()
    result = selector.find_valid_plans(building_positions, d)
    print(result)

if __name__ == "__main__":
    main()

算法及复杂度

  • 算法:滑动窗口
  • 时间复杂度: O ( N ) \mathcal{O(N)} O(N),其中 N N N是建筑物数量
  • 空间复杂度: O ( 1 ) \mathcal{O(1)} O(1),只需要常数空间

题目链接

题解

题目难度:较难

知识点:位运算

解题思路:在思考这道题是,首先想到的可能是按照数据的顺序,一个一个数比较,标记出只出现一次的数,输出这个数即可,但是这个过程的复杂度很高,复杂度为n^2。
在考虑这道题时,我们可以先思考一个简单版本:一个数组只有一个数字只出现一次,其他的数字都出现了两次。怎么查出这个数?
这个题目强调有一个数字出现一次,其他的出现两次。所以我们想到了异或运算的性质:任何一个数字异或它自己都等于0。所以我们只需要从头到尾异或所有的数,这是整个过程中,两个相同的数据就会全部抵消掉了,就只会剩下那个不同的数据。所以,一个数据组中如果只有一个不同,异或整个数组后就可以找出它。所以,对于这到原题,我们需要考虑的就是把这整个数据组分为两个数组,每个数组只包括一个不同的数据,单独异或这两个数据就可以了。
有了这个思路后,我们还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为这个数肯定不为0,找出它的1的位置,标记这个位置,然后按照这个完整的数据中的数据,在这个标记的位置是否为1,就可以分为两个数据组,每个数据组只含有一个不同的数据,然后就可以找出这两个数字了。

解题

这是一道考察位运算的题。两个相同的数进行异或其结果为0。所以当所有值进行了一次异或后,最后的结果就是这两个不同值的异或结果。然后通过与运算和位移运算,找到异或后结果为1的位置,此位置所有为0的进行异或和所有为1的异或就是结果。

#include <bits stdc++.h>
using namespace std;
int a[1000001];
void getNumber(const int a[], int n, int&amp;num1, int&amp;num2)
{
    int OR= 0;
    int flag = 0;
    for(int i = 1; i &lt;= n; i++)
    {
         OR ^= a[i];
    }
    while((OR &amp; 1) == 0)
    {
        OR = OR &gt;&gt; 1;
        flag++;
    }
    for(int i = 1; i &lt;= n; i++)
    {
        if((a[i] &gt;&gt; flag) &amp; 1)
            num1 ^= a[i];
        else
            num2 ^= a[i];
    }
}
int main(void)
{
    int n = 0;
    while (~scanf("%d", &amp;a[n + 1])) ++n;
    int p, q;
    getNumber(a, n, p, q);
    if (p &gt; q) swap(p, q);
    printf("%d %d\n", p, q);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值