Middle-题目28:75. Sort Colors

本文介绍了一种特定的排序问题——三色排序,并提供了两种高效算法实现。一种是通过计数排序来统计每种颜色的数量,然后重新填充数组;另一种是通过交换排序,在一次遍历中完成排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目原文:
Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
题目大意:
有三个对象,分别是红色,白色,蓝色,对他们排序使得所有的颜色按照红色-白色-蓝色的顺序,这里使用0,1,2分别代表红色,白色,蓝色。

抽象成算法模型即:
给出一个数组,数组里面只有0,1,2三个数字,对其排序。
题目分析:
1. 朴素解法:既然是排序,调用Java的API即可。
2. 计数排序:先扫描一遍数组,统计有多少0,多少1,多少2,然后再扫描一遍数组,按0,1,2的个数分别填充数组。
3. 交换排序:从0开始记录红色和白色的插入位置,扫描数组,如果扫到当前位置是1,则与1应插入的位置交换,如果扫到当前位置是0,则先与1插入的位置交换,再与0插入的位置交换。(因为换到0的位置以后,1的位置也向后移动了)
源码:(language:c)
方法1略。
方法2:

void sortColors(int* nums, int numsSize) {
    int red=0,white=0,blue=0;
    for(int i = 0;i<numsSize;i++) {
        if(nums[i] == 0)
            red++;
        else if(nums[i] == 1)
            white++;
        else
            blue++;
    }
    for(int i=0;i < numsSize;i++) {
        if(red > 0) {
            red--;
            nums[i]=0;
        }
        else if(white > 0) {
            white--;
            nums[i]=1;
        }
        else
            nums[i]=2;
    }
}

方法3:

void sortColors(int* nums, int numsSize) {
    int Insert_Red=0,Insert_White=0;
    for(int i=0;i<numsSize;i++) {
      if(nums[i]==1) {    
           nums[i]=nums[Insert_White];
           nums[Insert_White++]=1;
      }
      else if(nums[i]==0) {   
           nums[i]=nums[Insert_White];
           nums[Insert_White++]=nums[Insert_Red];
           nums[Insert_Red++]=0;
      }

    }
}

成绩:
方法1:1ms,beats 3.63%,众数1ms,75.47%
方法2:0ms,beats 2.63%,众数0ms,97.37%
方法3:2ms,beats 2.63%
Cmershen的碎碎念:
方法2和方法3的时间复杂度都是O(n),但方法2扫了两遍数组,方法3扫了一遍,但多次提交都是方法2时间短。

function [all_sequences, all_pri, remaining_toa] = optimized_CDIF(filename, max_level, k_threshold, tolerance, min_pulse_sequence, min_total_pulses) % 读取数据并初始化 data = load(filename); toa_original = data(:,4); toa_original = sort(toa_original); remaining_toa = toa_original; % 计算初始参数 T_total = max(toa_original) - min(toa_original); absolute_max_pri = 1000000; % 1000ms PRI_max = min(T_total/2, absolute_max_pri); % 存储提取的序列 all_sequences = {}; all_pri = []; sequence_counter = 1; % 主循环:处理所有序列 while length(remaining_toa) >= min_total_pulses [sequence, pri, level, remaining_toa] = extract_next_sequence(remaining_toa, PRI_max, k_threshold, ... tolerance, min_pulse_sequence, min_total_pulses, max_level); if ~isempty(sequence) all_sequences{end+1} = sequence; all_pri(end+1) = pri; sequence_counter = sequence_counter + 1; fprintf('提取序列%d: PRI=%.1fus, 脉冲数=%d (分析层级:%d)\n', ... sequence_counter-1, pri, length(sequence), level); else break; end end % 显示最终结果 fprintf('\n===== 分析完成 =====\n'); fprintf('提取序列总数: %d\n', length(all_sequences)); fprintf('剩余脉冲数: %d\n', length(remaining_toa)); % 可视化最终结果 plot_final_results(all_sequences, remaining_toa); end function [sequence, pri, level, remaining_toa] = extract_next_sequence(toa, PRI_max, k_threshold, tolerance, … min_pulse_sequence, min_total_pulses, max_level) sequence = []; pri = []; level = []; current_level = 1; % CDIF分析循环(不移除图形绘制) while current_level <= max_level cumulative_hist = zeros(1, ceil(PRI_max)); current_T_total = max(toa) - min(toa); % 构建累积直方图 for lvl = 1:current_level if length(toa) > lvl dtoa = toa(lvl+1:end) - toa(1:end-lvl); valid_indices = (dtoa >= 1) & (dtoa <= PRI_max); dtoa = dtoa(valid_indices); for i = 1:length(dtoa) idx = min(ceil(dtoa(i)), length(cumulative_hist)); cumulative_hist(idx) = cumulative_hist(idx) + 1; end end end % 计算门限并寻找候选PRI thresholds = k_threshold * current_T_total ./ (1:length(cumulative_hist)); candidate_pri = []; for pri_val = 1:length(cumulative_hist) if cumulative_hist(pri_val) > thresholds(pri_val) % 跳过过小值(降噪) if pri_val < 10, continue; end % 检查二倍值 double_pri = 2 * pri_val; if double_pri <= length(cumulative_hist) && cumulative_hist(double_pri) > thresholds(double_pri) candidate_pri(end+1) = pri_val; else candidate_pri(end+1) = pri_val; end end end % 尝试提取序列 if ~isempty(candidate_pri) candidate_pri = sort(candidate_pri); for i = 1:length(candidate_pri) tolerance_val = candidate_pri(i) * tolerance; [sequence, new_toa] = extract_sequence(toa, candidate_pri(i), tolerance_val, min_pulse_sequence); if ~isempty(sequence) pri = candidate_pri(i); level = current_level; remaining_toa = new_toa; return; end end end current_level = current_level + 1; end end function plot_final_results(all_sequences, remaining_toa) % 创建新图形 figure(‘Position’, [100, 100, 1200, 800], ‘Name’, ‘CDIF脉冲分选结果’); hold on; grid on; title(‘CDIF脉冲分选结果’); xlabel(‘到达时间 (us)); ylabel(‘脉冲序列’); % 确定颜色方案 colors = lines(length(all_sequences)); % 确定Y轴位置范围 max_y = max(1, length(all_sequences)); % 确保至少为1 y_min = -0.5; y_max = max_y + 0.5; % 为每个序列创建不同的Y轴位置 for i = 1:length(all_sequences) % 计算当前序列的平均PRI sequence_toa = sort(all_sequences{i}); sequence_diffs = diff(sequence_toa); avg_pri = mean(sequence_diffs(sequence_diffs > 0)); % 为序列中的每个脉冲分配相同的Y值 (i) y_value = i * ones(size(all_sequences{i})); % 绘制序列脉冲 scatter(all_sequences{i}, y_value, 80, colors(i,:), 'filled', 'o'); % 标记序列号和PRI值 min_time = min(all_sequences{i}); text(min_time - max(all_sequences{i})*0.02, i, ... sprintf('序列%d (PRI=%.1fus)', i, avg_pri), ... 'VerticalAlignment', 'middle', 'FontWeight', 'bold', ... 'BackgroundColor', 'white', 'Margin', 1); % 添加序列趋势线 plot(sequence_toa, i * ones(size(sequence_toa)), ... 'Color', colors(i,:), 'LineWidth', 1.5); end % 绘制剩余脉冲(位于Y=0位置) if ~isempty(remaining_toa) y_remaining = zeros(size(remaining_toa)); scatter(remaining_toa, y_remaining, 50, [0.5 0.5 0.5], 'x', 'LineWidth', 1.5); text(min(remaining_toa) - max(all_sequences{end})*0.02, 0, '未分类脉冲', ... 'Color', [0.5 0.5 0.5], 'FontWeight', 'bold', ... 'VerticalAlignment', 'middle', 'BackgroundColor', 'white'); end % 设置Y轴范围和标签 yticks(0:max_y); ytick_labels = arrayfun(@(i) {sprintf('序列%d', i)}, 1:max_y); if ~isempty(remaining_toa) ytick_labels{1} = '未分类脉冲'; end yticklabels(ytick_labels); % 添加网格和美观设置 set(gca, 'YGrid', 'on', 'XGrid', 'on', 'GridLineStyle', '--'); % 添加图例 legends = arrayfun(@(i) sprintf('序列%d', i), 1:length(all_sequences), 'UniformOutput', false); if ~isempty(remaining_toa) legends = [{'未分类脉冲'}, legends]; % 确保未分类在首位 end legend(legends, 'Location', 'eastoutside', 'FontSize', 10); % 调整视图范围 min_x = min(cellfun(@min, all_sequences)); max_x = max(cellfun(@max, all_sequences)); if ~isempty(remaining_toa) min_x = min(min_x, min(remaining_toa)); max_x = max(max_x, max(remaining_toa)); end x_range = max_x - min_x; xlim([min_x - x_range * 0.05, max_x + x_range * 0.05]); % 自动调整Y轴范围 ylim([y_min y_max]); hold off; end % 序列提取函数 (改进版) function [sequence, remaining] = extract_sequence(toa, pri, tolerance_val, min_length) sequence = []; remaining = toa; if length(toa) < min_length return; end best_sequence = []; best_length = 0; % 尝试不同的起点 for start_idx = 1:min(10, length(toa)) current_sequence = toa(start_idx); current_time = toa(start_idx); last_index = start_idx; lost_count = 0; % 向前搜索 for j = (start_idx+1):length(toa) expected_time = current_time + pri; % 检查当前脉冲是否在期望时间附近 if toa(j) >= expected_time - tolerance_val && ... toa(j) <= expected_time + tolerance_val current_sequence(end+1) = toa(j); current_time = toa(j); last_index = j; lost_count = 0; % 重置丢失计数 % 检查是否可能丢失脉冲 elseif toa(j) > expected_time + tolerance_val % 检查是否在下一个期望时间附近 next_expected = expected_time + pri; if toa(j) >= next_expected - tolerance_val && ... toa(j) <= next_expected + tolerance_val % 接受丢失一个脉冲 current_sequence(end+1) = toa(j); current_time = toa(j); last_index = j; lost_count = 1; % 检查是否在更远的期望时间附近 elseif toa(j) > next_expected + tolerance_val % 检查是否在第二个丢失脉冲的位置 next_next_expected = next_expected + pri; if toa(j) >= next_next_expected - tolerance_val && ... toa(j) <= next_next_expected + tolerance_val % 接受丢失两个脉冲 current_sequence(end+1) = toa(j); current_time = toa(j); last_index = j; lost_count = 2; else % 如果脉冲差距太大,可能不是同一个序列 if lost_count >= 2 break; end end end end end % 检查序列长度 if length(current_sequence) > best_length best_sequence = current_sequence; best_length = length(current_sequence); end end % 验证序列长度 if best_length >= min_length sequence = best_sequence; % 从原始TOA中移除序列 [~, idx] = ismember(sequence, toa); remaining = toa; remaining(idx) = []; end end % 设置参数 max_level = 2; k_threshold = 0.2; tolerance = 0.05; min_pulse_sequence = 3; min_total_pulses = 5; % 运行优化的CDIF算法 [sequences, pris, remaining] = optimized_CDIF(‘PDW1.txt’, max_level, k_threshold, tolerance, min_pulse_sequence, min_total_pulses); 将上述代码中绘图函数,改为绘制结果的直方图以及门限函数,横轴为PRI纵轴为统计数
06-13
% 数据列: Year, Province, School, NOI_Medals, NOIP_Prizes % 读取数据 filename = 'D:/data4.xlsx'; data = readtable(filename, 'VariableNamingRule', 'preserve'); % 步骤2: 计算综合得分 (权重: NOI=0.7, NOIP=0.3) w_NOI = 0.7; % NOI权重 (可调整) w_NOIP = 0.3; % NOIP权重 (可调整) score = w_NOI * data.NOI_Medals + w_NOIP * data.NOIP_Prizes; data.Score = score; % 添加新列 % 步骤3: 按中学分组并拟合线性趋势模型 schools = unique(data.School); % 唯一中学列表 nSchools = numel(schools); results = table('Size', [nSchools, 4], 'VariableTypes', {'string', 'double', 'double', 'double'}, ... 'VariableNames', {'School', 'Slope', 'Intercept', 'RSquared'}); for i = 1:nSchools schoolName = schools{i}; idx = strcmp(data.School, schoolName); % 筛选当前中学数据 schoolData = data(idx, :); years = schoolData.Year; scores = schoolData.Score; % 归一化年份 (避免数值过大) yearsNorm = years - min(years); % 例如: 2011年变为0, 2012年变为1 % 检查数据点数量 (至少需要2个点拟合) if numel(yearsNorm) < 2 results.School(i) = schoolName; results.Slope(i) = NaN; results.Intercept(i) = NaN; results.RSquared(i) = NaN; continue; end % 拟合线性模型: Score ~ Year X = [ones(size(yearsNorm)), yearsNorm]; % 设计矩阵 [1, t] [b, ~, ~, ~, stats] = regress(scores, X); % b(1)=截距, b(2)=斜率 intercept = b(1); slope = b(2); rsquared = stats(1); % R²值 % 存储结果 results.School(i) = schoolName; results.Slope(i) = slope; results.Intercept(i) = slope; results.RSquared(i) = rsquared; end % 步骤4: 分析整体时间特征 (例如平均斜率) validIdx = ~isnan(results.Slope); meanSlope = mean(results.Slope(validIdx)); fprintf('所有中学竞赛水平的平均年增长率 (斜率): %.4f\n', meanSlope); % 步骤5: 可视化结果 (示例: 斜率分布直方图) figure; histogram(results.Slope(validIdx), 'BinWidth', 0.5); title('参赛中学竞赛水平年增长率分布'); xlabel('斜率 (\beta_i)'); ylabel('中学数量'); grid on; % 步骤6: 保存结果到CSV文件 writetable(results, 'school_trend_results.csv'); disp('结果已保存到 school_trend_results.csv'); 对空值进行线性插值,最后可视化显示shcool的名字
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值