算法代码题

本文详细解析了包括字符串匹配、链表操作、二叉树构建在内的多种算法题,涉及正则匹配、排列组合、翻转字符串、删除链表节点、重建二叉树等多个经典问题。通过递归和循环方法解决斐波那契数列、求解最小值、查找数组中特定数字等,并探讨了排序算法和查找算法的应用,如二分查找、二叉搜索树等。此外,还介绍了回溯法在矩阵路径和机器人运动范围问题中的应用,以及动态规划解决剪绳子和连续子数组最大和等问题。

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

< 记录下算法题 个人复习使用 >

面试代码题

数据结构

注:有些结构体指针方便书写我使用符号点’.'取值

<字符串>

1.剑指offer19题:正则匹配

思路:
如果当前字符后面字符后跟着*字符,则会出现几种情况:
当前所指的字符相同时 :1.字符串保持不变,模式后移两位(出现零次);2.字符串后移一位,模式串后移两位(出现一次);3.字符串后移一位,模式串保持不变(出现多次)
当前所指字符不同是:字符串保持不变,模式后移两位

bool matchCore(char *str, char *pat)
{
	if(*str == 0 && *pat == 0)
		return true;
	if(*str != 0 && *pat == 0)
		return false;
	//next is *
	if(*(pat+1) == '*' )
	{
		if(*pat == *str)
		{
			return matchCore(str, pat+2) || matchCore(str+1, pat+2) || matchCore(str+1, pat);
		}
		else
		{
			return matchCore(str, pat+2)
		}
	}
	if(*str == *pat || (*pat == '.' && *str != 0))
	 	return matchCore(str+1, pat+1)
	 return false;
}

2.字符串的排列组合

排列思路:
1.将字符串分为两部分,第一部分为第一个字符,第二个部分为后面的所有字符
2.重复1继续对后面的所有字符做全排
3.如果需要对重复字符处理,则只需要增加一个判断重复函数

//permutation(str, str);  call permutation function
void permutationCore(char*sBegin, char *str)
{
	if(sBegin == 0) 
	{
		//show str
		return;
	}
	for(char* Cstr = sBegin; *Cstr != '\0'; Cstr++)
	{
		//jugde repetition
		swap(*Cstr, *sBegin);
		permuatationCore(sBegin+1, str);
		swap(*Cstr, *sBegin);
	}
}

组合思路:
1.将字符串分为第一个字符和后面其他字符两部分
2.m个字符串取长度为n(0<=n<=m)的排列; 如果包含第一个字符,则后面n-1中取m-1个;不包含第一个字符,后面n-1中取m个

void combine(char str[], int lenth)
{
	vector<char> data;
	for (int i = 1; i <= lenth; i++)
	{
		combineCore(str, i, data);
	}
}
void combineCore(char str[], int n, vector<char> data)
{
	if (n == 0)
	{
		for (vector<char>::iterator it = data.begin(); it != data.end(); ++it)
		{
			cout << *it << " ";
		}
		cout << endl;
		return;
	}
	if (*str == '\0') return;
	data.push_back(*str);
	//m-1中取n-1个
	combineCore(str + 1, n - 1,data);
	data.pop_back();
	//m-1中取n个
	combineCore(str + 1, n,data);
}

举一反三:
如果要求摆放若然数字,只需要将数字的所有排列都求出来,然后依次判断每个排列是否满足要求。

3.字符串的翻转

思路:先翻转整个字符串,然后逐个翻转每个单词

void reverse(char *pbegin, char *pend);
char * reverseWord( char * data)
{
	//reverse whole string
	reverse(data, data + len(data));
	//reverse word
	char *pbegin = data, *pend = data;
	while(*pbegin != 0)
	{
		if(*pbegin == ' ')
		{
			pbegin++;
			pend++;
		}
		else if (pend == ' ')
		{
			reverse(pbegin, pend - 1);
			pbegin = pend + 1;
		}
		else
		{
			pend++;
		}
	}
}

T2:字符串的左转
思路:将N位左转,先把字符串以N位分为两部分,分别旋转两个字符串,然后旋转整个字符串;

<链表>

1.删除单链表的节点

在O(1)的时间复杂度删除链表的节点
思路:
struct node{
int val;
struct node *next;
}
pb为需要删除的链表;
pb->val = pb->next->val; pb->next = pb->next->next;
del 之前pb的下一个节点
注意点:
1.如果删除节点位于尾部(使用O(n)的方法处理)

2.删除链表中重复节点

思路:三个指针,一个指向当前节点,一个指向下一个节点,一个指向上一个节点
注意点:重复节点可能位于头部、中间、尾部;可能存在多个重复节点

3.链表中倒数第N个节点

思路:两个指针,并且这两个指针的步长保持k - 1
注意点:链表的长度是否大于N
举一反三:链表的中间节点问题等,只要是相关类似问题都可以采用双指针步长

4.链表中找环的起点

思路:
1.确定链表中存在环
2.确定环的大小
3.确定环的起点

5.链表的翻转

思路:使用三个指针、使用递归
注意点:翻转前链表的尾指针会变成翻转后的尾指针,需要保存

6.复杂链表的复制(链表节点有一个指向任意节点的指针)

思路:
1.创建复制节点,并将创建的每一个复制节点都挂载原始节点的后面,即
N’->next = N->next;
N->next = N’;
2.赋予复制节点的任意节点值,等价于N’->rand = N->rand->next;
3.分割两个链表

7.两个单链表公共节点

思路:
思路1.使用栈来做辅助空间
思路2.确定两个链表的长度,长的链表比短的链表先走(长-短)步

<树>

基本概念

(1)二叉搜索树不一定是完全二叉树,因此出现平衡二叉搜索树这个概念;二叉搜索树的左节点小于根节点,右节点大于根节点。
(2)完全二叉树和满二叉树,满二叉树最后一层也须是满叶子节点。

1.重建二叉树

根据前序遍历和后续遍历的集合,构建二叉树。
思路:采用递归的方式 core(preS, preE, inoS, inoE)
递归的终止条件 :前序集合只有一个变量,中序集合只有一个变量,且两个集合的变量相等。

//伪代码
BinaryTree* ConstructCore(
	int *preSta, int *preEnd,
	int* inordSta, int *inordEnd)
{
	int rootValue = preSta[0];
	BinaryTree *root = new BinaryTree();
	root->value = rootValue;
	root->left = root->righ = nullptr;

	if (preSta == preEnd)
	{
		if (inordSta == inordEnd && *inordSta == *preSta)
		{
			return root;
		}
		else
		{
			//err
		}
	}

	int *t = inordSta;
	while (t <= inordEnd && *t != rootValue)
		t++;

	int leftLen = t - inordSta;
	int *leftPreEnd = inordSta + leftLen;
	if (leftLen > 0 /*left*/)
	{
		root->left = ConstructCore(preSta+1, leftPreEnd, inordSta, t - 1 );
	}
	if (1/*right*/)
	{

	}
	return root;
}

2.二叉树的下一个节点

思路:三种情况,若节点有左子树,若节点有右子树,若节点没有子树(又分为为父节点的右孩子和父节点的左孩子)

3.a树是否为b树的子结构

bool trasfer(Tree *t, Tree *tm)
{
	if(t == NULL && tm == NULL)
		return false;
	if(equal(t.v,tm.v))
		bool hasSub = hasSubNode(t, tm)
	if<