leetcode代码模板

笔者目前正在刷力扣平台算法题,本文总结一下笔者在刷题过程中自己悟出来的代码模板,持续更新中…

二分算法-红蓝染色法:

(1)二分查找模板:

//开区间写法最为简洁,最不易出错,体现在以下几个方面:
//1.无需担心死循环的问题(如果真的出现死循环,说明是思路有问题,请不要怀疑是开区间的问题)
//2.染色时,不需要考虑mid+1,-1的问题,大大简化了染色过程需要思考的逻辑,只需把握好循环不变量即可,不必再考虑区间的开闭
//3.循环不变量的边界对称而简洁,易于记忆
class Solution {
public:
     int binarySearch(vector<int>& nums, int target){

        //注意1:开区间设定初始边界的时候,要注意左边界-1,右边界+1
        int left = 左边界-1, right = 右边界+1;

        //注意2:开区间的循环条件:left + 1 < right
        while(left + 1 < right){
            int mid = left + (right - left) / 2;
            //注意3:把握好循环不变量将很有助于分析最终的二分答案
            //循环不变量:
            //未确定区间为(left, right)
            //nums[left] 以及left左侧元素满足某一条件
            //nums[right] 以及rihgt右侧元素满足上述条件的对立面
            //上述的循环不变量将直接影响最终结果,循环结束,left+1 == right,且满足上述循环不变量
			
			//注意4:根据判断结果染色,这里left和right的位置需根据实际问题来染色
            (/*填写关于mid与目标值的关系*/ ? left : right) = mid;
        }
        return right;
     }
};

(2)二分答案模板:

class Solution {
public:
    long long binaryAns(vector<int>& ranks, int cars) {
		//注意1:使用局部函数(lamabda表达式)来定义check函数。返回值为bool类型
		//这样比重新定义一个check函数需要敲的代码量少
        auto check = [&](long long ans) {
            /*填写判断ans是否为答案的逻辑,返回值bool类型*/
        };

		//注意2:开区间设定初始边界的时候,要注意左边界-1,右边界+1
        int left = 左边界-1, right = 右边界+1;

		//注意3:二分。可以看出,二分答案的开区间二分非常简单,唯一需要注意的地方是
		//check检查了mid之后,应该染色左边界还是右边界?其他的写法一成不变,很有模板的韵味
        while(left + 1 < right){
            long long mid = left + (right - left) / 2;
			//注意4:根据判断结果染色,这里left和right的位置需根据实际问题来染色
            (check(mid) ? left : right) = mid;
        }
        return right;
    }
};


定长滑动窗口:

//假设滑动窗口固定长度为: n ,则代码模板如下:
class Solution {
public:
    int SlideWindow(vector<int>& nums, int k) {
        int length = nums.size();
		//在进入循环之前,必须先初始化好窗口为最左侧位置的情况
		//并且维护好这种情况下的相关变量

		//这里要首先判断一下初始化的结果是否满足题意,然后下面的第一次循环就不必
		//遍历第一种情况了,这么做是也是为了满足循环不变量[i - n, i)

        //循环不变量:滑动窗口[i - n, i),窗口长度固定为 n
        for (int i = n; i < length; i++) {
            //此时i位置为窗口本次循环的末位置下标,由于是开区间i,所以接下来要维护nums[i]的状态
            //而i-n位置为上一次循环的首位下标,我们通常也需要关注维护它的状态,使窗口左边界向右移动一位

			//以上操作进行完毕之后,此时窗口区间就变为闭区间[i - n + 1, i]了,长度还是n
			//下一次循环之前i++,区间再次变为半开半闭状态-[i - n, i)
        }
        return ...;
    }
};



不定长滑动窗口:

//不定长滑动窗口伪代码
class Solution {
public:
    long long slideWindow(vector<int>& nums, long long k) {
        int 需要维护的变量..., left = 0, ans = 0;
        for (int right = 0; right<nums.size(); right++){
            代码:在这里进行将nums[right]加入到窗口之后需要维护
            窗口的相关状态变量的操作,使其达到 "缩小左边界的条件"
            ans可能需要在这里维护
            while(满足缩小左边界的条件){
                代码:在这里进行缩小左边界所需维护窗口相关变量状态的操作
                ans可能需要在这里维护
                left++;
            }
            ans可能需要再这里维护
        }
        return ans;//返回答案
    }
};


单调栈:

(1)寻找左侧第一个小的元素:

  • 栈中存放的是数组的下标,而不是数组的值
  • 此模板适用于以下四种情况:
  • 寻找数组中所有元素左侧第一个比它小的元素
  • 寻找数组中所有元素左侧第一个比它大的元素
  • 寻找数组中所有元素右侧第一个比它小的元素
  • 寻找数组中所有元素右侧第一个比它大的元素
vector<int> ans(n, -1);
stack<int> st;
for (int i = 0; i < n; i++) {
	//应该递增栈,还是递减栈?这里可以这样思考:从右往左找,栈中存放的是答案
	//则栈一定要为目标量身定制一个栈,要找的是小的,则保证从栈顶到栈底递减即可,即
	//为 “寻找左侧第一个小的元素这个目标服务”, 因为这样子的话,即使栈顶元素不合适
	//(大于当前遍历元素),那栈的下一个元素仍然可能满足小于当前遍历的元素
	
	//解决了递增递减问题,下面讨论如何写出while这些代码:栈里面存放的是可能有比当前遍历
	//元素小的目标元素,也可能没有。我们要找的是比当前元素小的栈中的第一个元素(从栈顶向
	//下看)即,nums[i] > nums[st.top()])。那么就反过来,如果nums[i] <= nums[st.top()])
	//(到这里其实已经推出了while括号里面的条件,下文可以不看,也可以看看加深理解)
	//则说明当前栈顶元素不满足条件,并且后续也不可能再满足了,因为此时的nums[i]比它更
	//符合条件(这里是小),还更靠左,所所以栈顶元素就被淘汰了,直接出栈,再比较新的栈顶
	//元素,重复上述过程,直到找到符合条件的栈顶元素(这里是比nums[i]小)
	while (!st.empty() && nums[i] <= nums[st.top()]) {
		st.pop();
	}
	
	//while之后,代码走到这里有两种结果:
	//1.nums[i]在栈中找到了自己的真命天子-此时的栈顶元素 (栈中有比nums[i]还
	//  优秀的元素,这里的优秀指的是更小),且栈顶就是真命天子,此时栈非空
	
	//2.nums[i]把栈弹空了,仍然找不到自己的真命天子,此时栈空了
	
	//如果栈非空,说明是情况1.此时说明找到nums[i]左边第一个比它小
	//的元素了,这个元素就是栈顶元素:nums[st.top()],接下根据实际问题处理
	//维护nums[i]与nums[st.top()]的相关变量状态即可
	if (!st.empty()) {
		在这里维护nums[i]与st.top(),的关系,注意st.top()是下标
		例如我想将nums[i]左侧第一个比它大元素下标记录一下:
		ans[i] = st.top();	//ans[i]的值表示:nums[i]左侧第一个比它大的元素的下标
	}
	
	//不管最后nums[i]找到没找到自己的真命天子,她都被栈给感动了,因为对于情
	//况1.找到了,那自然很感动;而对于情况2,虽然没有找到,但是栈已经为此把自
	//己弹空了,这更令nums[i]感动,因此nums[i]毅然决定入栈来感谢栈的付出
	st.push(i);
}

注意事项:如果某个元素根本就不存在要找的关系,比如上述例子nums[3]左
侧的nums[0],nums[1],nums[2]都比它大,那么上述模板的做法是忽略不处理,
例如上述模板的nums[2]找不到符合条件的元素,那么ans[2]将等于其初始值-1


回溯算法:

//自己画树形图分析的时候,要时刻思考回溯三问:
//回溯三问:当前操作?	子问题?	下一个子问题?
//解释:回溯三问主要用于解决代码模板里面的 "当前操作" ,"子问题" 这两个代码块
//至于" 回溯" 这个代码块,是当前操作的逆过程,无需多言
//而刚开始的 "终止" 的相关逻辑也比较好想
//因此难点是剩下的两步:"当前操作?" ,  "子问题?"
//回溯的问题都是树形结构的,每一个节点都是一个子问题,如何通过当前操作,使当前问题
//变成规模更小的子问题?想清楚这一点,就可以很容易的画出树形图,然后当前操作和子问题的代码
//也会一目了然

void backtracking(参数){
	if(终止条件){
		存放结果;
		return;
	}
	
	for(选择: 本层集合中的元素(树中节点孩子的数量就是集合大小)){
		处理节点;						//当前操作
		backtracking(路径,选择列表);	//子问题
		回溯,撤销处理结果;				//回溯
	}
}


### 如何在本地环境中运行 LeetCode 代码 要在本地环境中运行 LeetCode 代码,需要完成以下几个方面的配置: #### 插件安装与账户配置 首先,在 IntelliJ 系列 IDE 中安装并配置 LeetCode 插件。打开 IDE 设置 (`File -> Settings`) 并导航至 `Tools -> LeetCode Plugin`。在此处选择所使用的 LeetCode 网站(如 leetcode.com 或 leetcode-cn.com),并输入登录名和密码以完成账户绑定[^1]。 #### 文件命名模板调整 默认情况下,LeetCode 插件会生成带有中文名称的文件路径,这可能导致某些操作系统无法正常识别或编译这些文件。因此建议修改文件命名模板为英文形式。可以通过自定义模板实现这一目标,例如将文件命名为 `[${question.frontendQuestionId}]_${question.title}` 的格式来替代原始模板[^2]。 #### 配置语言环境和支持库 为了能够在本地成功执行从 LeetCode 导入的问题代码片段,还需要确保已正确设置了对应编程语言的支持库以及框架结构。比如对于 Java 来说,可能需要用到 JUnit 测试框架来进行单元测试验证;而对于 Python,则需确认虚拟环境下已经包含了必要的依赖包。 此外,当通过插件下载某个具体算法挑战时,通常只提供了函数声明部分而缺少完整的程序入口逻辑。这时就需要手动补充 main 函数或者其他驱动代码以便于实际调用待测方法[^4]。 以下是针对几种常见开发语言的一个简单例子展示如何构建可独立运行的应用程序: ```java // Example of setting up a runnable Java program with the given function signature. public class Solution { public int addTwoNumbers(int num1, int num2){ return num1 + num2; } public static void main(String[] args) { Solution sol = new Solution(); System.out.println(sol.addTwoNumbers(5,7)); // Output should be 12 } } ``` ```python # An example setup for running python solutions locally. def twoSum(nums, target): """ :type nums: List[int] :type target: int :rtype: List[int] """ hashmap = {} for i in range(len(nums)): complement = target - nums[i] if complement in hashmap: return [hashmap[complement],i ] hashmap[nums[i]] = i if __name__ == "__main__": result = twoSum([2,7,11,15],9) print(result) #[0,1] ``` 以上展示了如何基于特定问题创建能够直接被执行的整体解决方案脚本。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuiStar_李什么恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值