Algorithm
本周选择的算法题是:Earliest Possible Day of Full Bloom。
规则
You have n
flower seeds. Every seed must be planted first before it can begin to grow, then bloom. Planting a seed takes time and so does the growth of a seed. You are given two 0-indexed integer arrays plantTime
and growTime
, of length n
each:
plantTime[i]
is the number of full days it takes you to plant theith
seed. Every day, you can work on planting exactly one seed. You do not have to work on planting the same seed on consecutive days, but the planting of a seed is not complete until you have workedplantTime[i]
days on planting it in total.growTime[i]
is the number of full days it takes theith
seed to grow after being completely planted. After the last day of its growth, the flower blooms and stays bloomed forever.
From the beginning of day 0
, you can plant the seeds in any order.
Return the earliest possible day where all seeds are blooming.
Example 1:
Input: plantTime = [1,4,3], growTime = [2,3,1]
Output: 9
Explanation: The grayed out pots represent planting days, colored pots represent growing days, and the flower represents the day it blooms.
One optimal way is:
On day 0, plant the 0th seed. The seed grows for 2 full days and blooms on day 3.
On days 1, 2, 3, and 4, plant the 1st seed. The seed grows for 3 full days and blooms on day 8.
On days 5, 6, and 7, plant the 2nd seed. The seed grows for 1 full day and blooms on day 9.
Thus, on day 9, all the seeds are blooming.
Example 2:
Input: plantTime = [1,2,3,2], growTime = [2,1,2,1]
Output: 9
Explanation: The grayed out pots represent planting days, colored pots represent growing days, and the flower represents the day it blooms.
One optimal way is:
On day 1, plant the 0th seed. The seed grows for 2 full days and blooms on day 4.
On days 0 and 3, plant the 1st seed. The seed grows for 1 full day and blooms on day 5.
On days 2, 4, and 5, plant the 2nd seed. The seed grows for 2 full days and blooms on day 8.
On days 6 and 7, plant the 3rd seed. The seed grows for 1 full day and blooms on day 9.
Thus, on day 9, all the seeds are blooming.
Example 3:
Input: plantTime = [1], growTime = [1]
Output: 2
Explanation: On day 0, plant the 0th seed. The seed grows for 1 full day and blooms on day 2.
Thus, on day 2, all the seeds are blooming.
Constraints:
n == plantTime.length == growTime.length
1 <= n <= 105
1 <= plantTime[i], growTime[i] <= 104
Solution
impl Solution {
pub fn earliest_full_bloom(plant_time: Vec<i32>, grow_time: Vec<i32>) -> i32 {
let (mut current_grow_time, mut current_plant_time) = (0, 0);
let mut range: Vec<usize> = (0..plant_time.len()).collect();
range.sort_by_key(|k| -grow_time[*k]);
for i in range {
current_plant_time = current_plant_time + plant_time[i];
current_grow_time = current_grow_time.max(current_plant_time + grow_time[i]);
}
current_grow_time
}
}
Review
Difference between Software Architecture & Design
有点说不清楚两者之间的关系,从软件生产活动上看,架构偏抽象的名词,宏观上可以从技术战略和系统架构出发,为软件制定标准和指引,确定设计方法、工具和技术选型;也可以从微观出发,为软件或组件创建详细设计的文档等。设计偏具体的动词,设计动作贯穿在软件活动的每一层,比如概念设计、详细设计、原型设计等。
Tip
比 /TMP/FILES 更好用的临时文件服务: TEMP.SH。
Share
Nativefier 是一个可以将任何 web 页面打包成 Mac App 的工具,它的实现原理也很简单。
当在终端调用 nativefier 'any_web_app.com'
时:
- ‘any_web_app.com’ 会作为命令行参数通过 cli 接口传到 build 模块中:
buildNativefierApp(options).catch((error) => {
log.error('Error during build. Run with --verbose for details.', error);
});
- build 模块负责采集信息,并封装成 options,长这样:
export interface ElectronPackagerOptions extends electronPackager.Options {
arch: string;
portable: boolean;
platform?: string;
targetUrl: string;
upgrade: boolean;
upgradeFrom?: string;
}
export interface AppOptions {
packager: ElectronPackagerOptions;
nativefier: {
accessibilityPrompt: boolean;
alwaysOnTop: boolean;
backgroundColor?: string;
basicAuthPassword?: string;
basicAuthUsername?: string;
blockExternalUrls: boolean;
bookmarksMenu?: string;
bounce: boolean;
browserwindowOptions?: BrowserWindowOptions;
clearCache: boolean;
counter: boolean;
crashReporter?: string;
disableContextMenu: boolean;
disableDevTools: boolean;
disableGpu: boolean;
disableOldBuildWarning: boolean;
diskCacheSize?: number;
electronVersionUsed?: string;
enableEs3Apis: boolean;
fastQuit: boolean;
fileDownloadOptions?: Record<string, unknown>;
flashPluginDir?: string;
fullScreen: boolean;
globalShortcuts?: GlobalShortcut[];
hideWindowFrame: boolean;
ignoreCertificate: boolean;
ignoreGpuBlacklist: boolean;
inject?: string[];
insecure: boolean;
internalUrls?: string;
lang?: string;
maximize: boolean;
nativefierVersion: string;
processEnvs?: string;
proxyRules?: string;
quiet?: boolean;
showMenuBar: boolean;
singleInstance: boolean;
strictInternalUrls: boolean;
titleBarStyle?: TitleBarValue;
tray: TrayValue;
userAgent?: string;
userAgentHonest: boolean;
verbose: boolean;
versionString?: string;
width?: number;
widevine: boolean;
height?: number;
minWidth?: number;
minHeight?: number;
maxWidth?: number;
maxHeight?: number;
x?: number;
y?: number;
zoom: number;
};
}
- 经过 build 的处理后,options 实质上是一个抹平了平台之间差异的 skinny-model,如 exe、dmg,而且 bundleId 之类的取值也确定下来了,为后续基于 Electron 打包作准备,同时这个过程还会把应用的 icon 下载下来:
// inferIcon.ts
if (!iconUrl) {
log.debug('Could not infer icon from store');
return undefined;
}
return downloadFile(iconUrl);
// helpers.ts
export function downloadFile(
fileUrl: string,
): Promise<DownloadResult | undefined> {
log.debug(`Downloading ${fileUrl}`);
return axios
.get<Buffer>(fileUrl, {
responseType: 'arraybuffer',
})
.then((response) => {
if (!response.data) {
return undefined;
}
return {
data: response.data,
ext: path.extname(fileUrl),
};
});
}
- 确认好所有信息后,通过 electron-packager 执行标准化的打包动作即可,打包也就是往某个目录写入文件:
log.info('\nPreparing Electron app...');
const tmpPath = getTempDir('app', 0o755);
await prepareElectronApp(options.packager.dir, tmpPath, options);
打包完,启动应用时:
- 从包中取出 targetUrl(是之前 options 的一部分),包装为 appArgs 对象 :
// Take in a URL on the command line as an override
if (urlArgv.length > 0) {
const maybeUrl = urlArgv[0];
try {
new URL(maybeUrl);
appArgs.targetUrl = maybeUrl;
log.info('Loading override URL passed as argument:', maybeUrl);
} catch (err: unknown) {
log.error(
'Not loading override URL passed as argument, because failed to parse:',
maybeUrl,
err,
);
}
}
- 用 WebContents 开一个容器展示页面:
if (appArgs.targetUrl) {
await mainWindow.loadURL(appArgs.targetUrl);
}
无论是打包过程还是启动过程,这里面省略了太多的细节,如参数解析、检查更新、事件绑定等等。
目前为止,Nativefier 是一个拥有 31.9k Star 的开源项目,非常赞。