2026-08-12:统计下标的相反奇偶性得分。用go语言,给定一个整数数组,需要为数组中的每个位置计算一个分数。这个分数等于:在当前索引右侧的所有元素中,与当

35 阅读5分钟

2026-08-12:统计下标的相反奇偶性得分。用go语言,给定一个整数数组,需要为数组中的每个位置计算一个分数。这个分数等于:在当前索引右侧的所有元素中,与当前元素奇偶性不同(即一个是奇数,另一个是偶数)的元素个数。最终返回一个与原数组等长的数组,按顺序给出每个索引对应的分数。

1 <= nums.length <= 100。

1 <= nums[i] <= 100。

输入: nums = [1,2,3,4]。

输出: [2,1,1,0]。

解释:

nums[0] = 1,为奇数。因此,下标 j = 1 和 j = 3 满足条件,所以下标 0 的分数为 2。

nums[1] = 2,为偶数。因此,下标 j = 2 满足条件,所以下标 1 的分数为 1。

nums[2] = 3,为奇数。因此,下标 j = 3 满足条件,所以下标 2 的分数为 1。

nums[3] = 4,为偶数。因此,没有下标满足条件,所以下标 3 的分数为 0。

因此,answer = [2, 1, 1, 0]。

题目来自力扣3917。

算法的大体过程:

步骤一:初始化数据结构

  • 获取输入数组 nums 的长度 n
  • 创建一个与 nums 等长的整型切片(数组)ans,用来存放每个位置最终计算出的分数。
  • 创建一个长度为 2 的整型数组 cnt,用来动态记录在从右向左遍历过程中,已经遇到过的偶数和奇数的个数。通常约定 cnt[0] 存放偶数个数,cnt[1] 存放奇数个数,初始都为 0。

步骤二:从右向左遍历数组 使用循环,索引 in-1 递减到 0,逐步处理每一个元素。这么做的目的是保证当我们处理位置 i 时,所有在它右侧的元素(即索引大于 i 的元素)都已经被统计进了 cnt 中。

对于当前索引 i,执行以下子步骤:

  1. 判断当前元素的奇偶性
    nums[i] & 1 得到当前数字的奇偶标记 x。如果 nums[i] 是奇数,x1;如果是偶数,x0

  2. 查询右侧相反奇偶性的个数
    题目要求的分数是:在当前索引右侧,与当前元素奇偶性不同的元素个数。
    既然当前元素的奇偶性是 x,那么与之相反的奇偶性就是 x ^ 1(异或运算将 0110)。
    cnt 数组中,cnt[x ^ 1] 存放的,恰好就是已经扫描过的右侧元素中,奇偶性为 x ^ 1 的个数。
    cnt[x ^ 1] 的值赋给 ans[i],即得到位置 i 的得分。

  3. 更新计数器
    当前元素自身现在也要成为“右侧元素”的一部分(供更左侧的索引查询)。因此,将它按奇偶性计入 cnt 中,即执行 cnt[x]++。这样,当遍历到更左边的索引时,当前元素就已经被正确统计在内了。

步骤三:返回结果

  • 循环结束后,ans 中已经按顺序存储了每个索引对应的分数,直接返回 ans 即可。

具体执行示例(输入 [1,2,3,4])

  • 初始:cnt = [0, 0]
  • i=3:nums[3]=4,偶数 x=0;右侧相反奇偶性个数 cnt[1]=0ans[3]=0;然后 cnt[0] 加 1 → cnt=[1,0]
  • i=2:nums[2]=3,奇数 x=1;右侧相反奇偶性个数 cnt[0]=1ans[2]=1;然后 cnt[1] 加 1 → cnt=[1,1]
  • i=1:nums[1]=2,偶数 x=0;右侧相反奇偶性个数 cnt[1]=1ans[1]=1;然后 cnt[0] 加 1 → cnt=[2,1]
  • i=0:nums[0]=1,奇数 x=1;右侧相反奇偶性个数 cnt[0]=2ans[0]=2;然后 cnt[1] 加 1 → cnt=[2,2]
  • 最终得到 ans = [2, 1, 1, 0],与题目描述一致。

复杂度分析

  • 时间复杂度:算法只对数组进行了一次从右向左的遍历,循环内部只包含常数次位运算、数组访问和自增操作。整体时间复杂度为 O(n),其中 n 为数组长度。
  • 额外空间复杂度:除了输入数组外,算法额外使用了一个长度为 n 的结果数组 ans 和一个固定大小为 2 的计数数组 cnt。如果不将输出数组计入额外空间,则辅助空间为 O(1);若将必要的输出结构也视为额外空间,则总额外空间复杂度为 O(n)。一般在该类问题中,输出数组是必需的,因此可以说总的额外空间复杂度是 O(n)

Go完整代码如下:

package main

import (
	"fmt"
)

func countOppositeParity(nums []int) []int {
	n := len(nums)
	ans := make([]int, n)
	cnt := [2]int{}
	for i := n - 1; i >= 0; i-- {
		x := nums[i] & 1  // x 的奇偶性
		ans[i] = cnt[x^1] // 查询右侧奇偶性不等于 x(即 x^1)的元素个数
		cnt[x]++
	}
	return ans
}

func main() {
	nums := []int{1, 2, 3, 4}
	result := countOppositeParity(nums)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

from typing import List

def count_opposite_parity(nums: List[int]) -> List[int]:
    n = len(nums)
    ans = [0] * n
    cnt = [0, 0]  # cnt[0] 记录右侧偶数个数,cnt[1] 记录右侧奇数个数
    for i in range(n - 1, -1, -1):
        parity = nums[i] & 1          # 当前元素的奇偶性,0为偶,1为奇
        ans[i] = cnt[parity ^ 1]      # 右侧与当前奇偶性不同的元素个数
        cnt[parity] += 1
    return ans

if __name__ == "__main__":
    nums = [1, 2, 3, 4]
    result = count_opposite_parity(nums)
    print(result) 

在这里插入图片描述

C++完整代码如下:

#include <iostream>
#include <vector>

std::vector<int> countOppositeParity(const std::vector<int>& nums) {
    int n = nums.size();
    std::vector<int> ans(n);
    int cnt[2] = {0, 0}; // cnt[0] 偶数个数,cnt[1] 奇数个数
    for (int i = n - 1; i >= 0; --i) {
        int parity = nums[i] & 1;      // 当前元素的奇偶性,0偶1奇
        ans[i] = cnt[parity ^ 1];      // 右侧不同奇偶性的元素个数
        cnt[parity]++;
    }
    return ans;
}

int main() {
    std::vector<int> nums = {1, 2, 3, 4};
    std::vector<int> result = countOppositeParity(nums);
    for (int x : result) {
        std::cout << x << " ";
    }
    std::cout << std::endl;
    return 0;
}

在这里插入图片描述