Python技术迷

男朋友说我自己婚前买了房就分手,怎么破?

这男朋友急啥呢,急到房子还没买,分手先挂嘴边了。

女生工作稳定,自己有能力婚前买个三房,还说能当婚房,这放很多人眼里不就是挺靠谱吗?结果男朋友不高兴了,说要两个人一起买,买大的好的。听着像规划未来,细品又有点别扭。

Image

你想一起买,可以谈预算、谈城市、谈贷款压力,哪怕说“我也想参与这个家”,都正常。但一上来就是“你买我就分手”,这味儿就变了,像是在抢方向盘。

房子是资产,也是底气。尤其婚前自己能买,不偷不抢不啃老,凭什么先被吓一跳。真要结婚,应该是两个人一起把日子过稳,不是先把对方的选择权按住。

要我看,先别急着选房还是选人,先看看这个人到底是在想共同生活,还是在怕你太有退路。


算法题:输出比赛匹配对

比赛对阵表这题,最容易写歪的地方不是括号,是轮次。

输入 n = 8,队伍编号从 1 到 8,实力已经排好序。第一名打第八名,第二名打第七名,这个没啥好争的。麻烦在下一轮:上一轮生成的匹配结果,本身又要继续被当成一个“队伍”参与配对。

比如第一轮是这样:

(1,8)
(2,7)
(3,6)
(4,5)

下一轮不是随便拼,而是继续头尾匹配:

((1,8),(4,5))
((2,7),(3,6))

最后得到:

(((1,8),(4,5)),((2,7),(3,6)))

这地方我一般不先想递归。递归当然能做,但这题的数据推进很直,像一排人站队,每轮把最左和最右拉出来打一场,然后形成新的一排。用数组模拟,反而不容易出错。

代码可以这么写:

classSolution{

public String findContestMatch(int n){
        String[] round = new String[n];

for (int i = 0; i < n; i++) {
            round[i] = String.valueOf(i + 1);
        }

int size = n;
while (size > 1) {
            String[] next = new String[size / 2];

int left = 0;
int right = size - 1;
int idx = 0;

while (left < right) {
                next[idx++] = "(" + round[left] + "," + round[right] + ")";
                left++;
                right--;
            }

            round = next;
            size = next.length;
        }

return round[0];
    }
}

我不太喜欢在这里硬塞很多数学推导,没必要。你盯住 round 这个数组就行,它每一轮表示“当前还在比赛里的位置”。

第一次:

round = ["1","2","3","4","5","6","7","8"]

配完以后变成:

round = ["(1,8)","(2,7)","(3,6)","(4,5)"]

再配一次:

round = ["((1,8),(4,5))","((2,7),(3,6))"]

最后剩一个,就是答案。

这里有个小坑,别把 n 当成固定长度一路用到底。每打一轮,队伍数量都会减半,所以循环里要维护一个当前长度 size。如果还用原来的 n 去扫数组,后面不是数组越界,就是拼出来一堆空值。

这题还有一种写法,用 List<String> 会更顺手一点,尤其是面试现场写代码,少处理数组长度。

import java.util.ArrayList;
import java.util.List;

classSolution{

public String findContestMatch(int n){
        List<String> teams = new ArrayList<>();

for (int id = 1; id <= n; id++) {
            teams.add(String.valueOf(id));
        }

while (teams.size() > 1) {
            List<String> nextRound = new ArrayList<>();
int l = 0;
int r = teams.size() - 1;

while (l < r) {
                String match = "(" + teams.get(l) + "," + teams.get(r) + ")";
                nextRound.add(match);
                l++;
                r--;
            }

            teams = nextRound;
        }

return teams.get(0);
    }
}

我更倾向第二种,代码读起来像真实比赛推进:本轮队伍进来,配完生成下一轮。没有额外状态,也不用猜某个下标到底属于第几轮。

复杂度也很干净。每一轮都要处理当前所有队伍的一半,整体看下来,每个编号会被拼进字符串里,括号和逗号也会不断增加,所以时间主要花在字符串构造上。按算法题的口径,可以认为模拟轮次是 O(n log n) 级别;空间就是保存每轮结果,O(n)。

这题别想复杂。它不是让你算冠军,也不是让你真的模拟胜负。它只是让你按规则把对阵表打印出来。

头尾配对,生成下一轮,直到只剩一个字符串。停在这里就够了。