
我平时都使用哪些AI工具——Raycast AI开启PC Agent时代
这篇博客总结了作者在AI工具使用上的经验,特别是如何通过Raycast AI提升工作效率。作者认为AI工具本质上是大脑的延伸,传统工具如Notion等主要解放了双手,而AI工具则进一步减轻了大脑负担。Raycast AI成为作者的主力平台,因其结合本地工具和多模态功能,提供了更强的智能和功能性,超越了之前使用的POE平台。
全排列问题涉及将n个不同元素中任取m个元素的排列,特别是m=n时的全排列。文中介绍了递归DFS与剪枝方法来解决全排列问题,避免重复排列的产生,并提供了C#代码实现。此外,还讨论了如何找到下一个排列数的算法,强调了从后向前查找升序对和逆序排列的步骤,以实现字典序的排列。
排列 (Permutation) 是将相异对象或符号根据确定的顺序重排。每个顺序都称作一个排列。
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
全排列问题常出现在串(string) 相关的问题中。
例题:
长度为n的串的全排列问题可以分为以下的子问题结构:
最后的结果显然为 a+b
那么如何得到长度为n-1的串的排列数呢?
我们先固定一种串的排列方式,通过字符交换的方式,依次固定第i个字符,直到固定第n个字符时即为一种排列方式。
遍历途中对于固定的第i个字符,剩下的 (n-i) 个字符,则是需要递归处理的子问题。
但是,这种方法对于含有重复元素的集合会产生重复串(不适用重复元素)。
按照上述的最佳子结构关系,以串 1234
为例构建递归如下图所示,边界情况为子串长度=1:
我们不妨思考一下,为什么会产生重复串呢?
因为在交换的时候,对于固定位chs[i]
,后面若有两个重复字符,就会与之交换两次,虽然当时是不重复的,但在后续的交换中就会产生重复串。
如串abccd
,在固定a
时会与c
交换两次,生成两个串cbacd
和cbcad
。虽然此时这是不重复的,但我们在DFS树中更深入一点,在cbacd
这个分支里,固定位到a
时,也会因交换产生cbcad
这个串,这样就产生了重复。
因此,如果我们在分支的上游就排除了相同字符交换产生的分支(剪枝),不仅可以避免重复,还可以避免大量重复计算。
<img src="https://picgo-1308055782.cos.ap-chengdu.myqcloud.com/picgo-new/202304222208325.png" style="zoom:50%;" />
具体的实现,我们可以通过一个HashSet(其内的元素不允许重复,具有集合的特征,详见容器篇)来记录当前交换过程内所有已经交换过的字符来实现剪枝。
C#题解如下:
public class Permutation
{
static public List<string> Result = new List<string>();
static T[] Swap<T>(T[] source, int i1, int i2)
{
var t = source[i2];
source[i2] = source[i1];
source[i1] = t;
return source;
}
static public string[] Recursively(string str)
{
var candidate = str.ToCharArray();
Recursively(candidate, 0);
var res = Result.ToArray();
Result.Clear();
return res;
}
static void Recursively(char[] charSet, int start)
{
if (start == charSet.Length - 1)
{
var str = new String(charSet);
Console.WriteLine(str);
Result.Add(str);
}
var set = new HashSet<char>();
for (int i = start; i < charSet.Length; i++)
{
if (i == start || charSet[i] != charSet[start])
{
if (set.Contains(charSet[i])) continue;
set.Add(charSet[i]);
Swap(charSet, start, i);
Recursively(charSet, start + 1);
Swap(charSet, start, i); // 还原变化
}
}
}
}
一个(数字)序列的字典序是这些数字(如 {1, 2, 3, 4})组成的串大小(如1234)按升序排列的顺序,下一个排列就是对应串 (如12354
) 在字典序中的下一个序列 (如12435
)。
为了得到下一个更大的最小序列数(比当前大,但增加的幅度尽量小),我们构造如下算法要求:
为了增大的尽量小,我们要满足以下要求:
最后,我们构造算法如下:
(i,j)
,满足 A[i] < A[j]
。此时 [j,end)
必然是降序[j,end)
从后向前 查找第一个满足 A[i] < A[k]
的 k
。A[i]
、A[k]
分别就是上文所说的「小数」、「大数」A[i]
与 A[k]
交换[j,end)
必然是降序,逆置 [j,end)
,使其升序[begin,end)
为一个降序顺序,则直接跳到步骤 4【最大序列跳回最小序列】C# 实现为:
public void NextPermutation(int[] nums)
{
int i;
for (i = nums.Length - 1; i > 0; i--)
{
if (nums[i - 1] < nums[i]) // 找到第一个升序对
{
for (int j = nums.Length - 1; j >= i; j--)
{
if (nums[j] > nums[i - 1]) // 找到最小交换位置
{
Swap(nums, j, i - 1);
break;
}
}
break;
}
}
int left = i, right = nums.Length - 1;
while (left < right) // 逆序排列
{
Swap(nums, left, right);
left++;
right--;
}
}
直接把串化为字符数组,然后对这个数组排序,得到初始字典序,反复求下一个排列直到最大排序。
这个方法的优势在于:没有递归栈,省去了反复函数调用的开销。
作者: ChlorineC
创建于: 2023-04-28 16:44:00
更新于: 2025-01-05 09:03:00
版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
这篇博客总结了作者在AI工具使用上的经验,特别是如何通过Raycast AI提升工作效率。作者认为AI工具本质上是大脑的延伸,传统工具如Notion等主要解放了双手,而AI工具则进一步减轻了大脑负担。Raycast AI成为作者的主力平台,因其结合本地工具和多模态功能,提供了更强的智能和功能性,超越了之前使用的POE平台。
作者回顾了自己从使用IE到Chrome、Edge,再到Arc浏览器的经历,强调Arc的创新设计和功能,但因性能问题决定寻找替代品,最终选择了Vivaldi浏览器,并通过配置还原Arc的部分体验。
作者分享了个人博客框架迭代历程:从Hexo迁移到Astro的尝试,到发现Elog平台带来的启发,最终思考将Notion作为内容管理系统的新方案。文章重点描述了作者对博客系统的核心需求——解决创作同步问题,以及在探索NotionNext等解决方案过程中遇到的技术限制和思考。
使用VS Code的独立配置功能,可以为不同项目创建特定的配置文件,解决了在公司环境中因安全合规要求而无法使用第三方插件的问题。通过配置云同步和工作区单独配置,满足日常开发需求。推荐使用Codeium作为开源解决方案。