LeetCode(力扣)新手食用指南
Ice_Su1ka
编辑于 2024年04月21日 10:16

    有人相爱,有人夜里开车看海,有人leetcode第一题都做不出来。

        ----- LeetCode用户 小金和他自己 from 力扣评论区


    前言

    漫漫刷题路,LeetCode是各位刷题人无法错开的一个坎,而好多人在第一题就卡住了——不是因为题不会,而是因为不知道怎么写才能正确通过💦。

    LeetCode因为输入输出方法和其他刷题软件有很大差别,所以很多经过传统OnlineJudge网站历练过的LeetCode新人会在输入输出的方式方法上面栽跟头。咱曾经也是LeetCode新人,在第一题的格式上面卡了很长时间。所以出现了这篇专栏(虽然隔了很久但是这篇文章是在咱在操场上跑步时候突然想出来的所以现在才出现)。

    此篇专栏旨在进行LeetCode的刷题入门技巧普及。


    声明

    本文所有语言均以LeetCode题目单第一题(两数之和https://leetcode-cn.com/problems/two-sum/)为例。

    本篇专栏未涉及的语言纯粹由于up主太菜自己不会而没写,故本篇专栏只有C、C++、Java、python四种语言。如果up后续进行了其他语言的学习,本篇专栏也(可能)会进行相应的更新。


    LeetCode与其他OJ的异同点

    LeetCode的编程思路,通俗来讲,是服务器端进行数据的输入,通过所写方法(在C语言中,是一个函数)的处理,返回相应的输出值。程序猿要做的工作是写一个方法/函数,进行题目要求的处理。

    而传统的OJ的编程思路,是对整个编程文件的运行检查,输入一个数表,通过整个程序的处理,输出一个数表或数字。

    LeetCode这种IO的思路,类似于一个超大型项目的实现。一个App不可能只有一个源文件,所以由服务器端进行参数的传递,在程序中,各个类/方法/函数各司其职,进行数据的处理和再传递。所以,LeetCode是不需要数据输入的方法/函数的,输出也不需要输出方法/函数,而且不需要import包,也不需要include头文件,这些都是服务器端给你准备好了的。你只需要写一个方法/函数,进行数据的处理,将处理结果返回(return)即可。

    LeetCode提供了线上编辑器和编译器,但是对于IDEA、PyCharm等IDE而言,完全无法实现面向tab编程(雾),所以为了方便从传统OJ过渡来,在主方法/主函数中,我们还是会添加IO方法以实现本地调试。


    概述

    一个普通的LeetCode程序会以这样的形式出现:

普通LeetCode题目

    在左上角,题目描述是题面本身和代码编辑区。评论区是各路程序员评(hua)论(shui)这道题解法的地方。题解则是这道题的示例代码和深度分析所在的地方,大家切记不要不加思考直接去题解区CV代码提交!提交记录则是自己的提交过的代码记录所在地,可以查看自己的历史代码。

    在写完一道题之后,如果想进行一道题在LeetCode线上的检查,可以点击 执行代码 按钮。只点击按钮的话,只会进行第一个示例的运行,如果点击右侧的下箭头,则会出现 执行示例 按钮,此时点击 执行示例 按钮之后,会运行所有示例,非常方便。

执行示例的结果

    如果这道题非常经典,你可以点击左上角的 收藏 按钮进行收藏(所以给我的专栏也来个收藏罢(被打死))。

    只知道这些技巧,已经对LeetCode的使用完全没有障碍了。所以我们开始进行各个语言本地化的方法说明。


1. Java:

    作为up主的主力语言,Java自然也是C位出镜。up主使用的IDE为IntelliJ IDEA。    

    首先是总览:

代码块
clike
自动换行
复制代码
package LeetCode;

import java.math.BigDecimal;
import java.util.*;

class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) {this.val = val;}
    ListNode(int val, ListNode next) {this.val = val; this.next = next;}
}
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

class Solution {
    static Scanner in = new Scanner(System.in);
    static int[] dx = {1, -1, 0, 0};
    static int[] dy = {0, 0, 1, -1};

    public static void main(String[] args) {
        int n = in.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) 
            nums[i] = in.nextInt();
        int target = in.nextInt();
      	Solution solution = new Solution();	//创建Solution类的实例solution
        System.out.println(Arrays.toString(solution.twoSum(nums, target)));	//直接调用solution中的twoSum方法进行输出。
    }

    public int[] twoSum(int[] nums, int target) {	//无需添加static
        int n = nums.length;
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return new int[]{i, j};
                }
            }
        }
        return new int[0];
    }
}
复制成功

    其中ListNode和TreeNode两个类是进行链表和二叉树题编写方便而加,我们主要来看Solution类里的内容:

    int[] dx和int[] dy两个数组是为了方便bfs算法而设置。

    in是一个Scanner类的创建,用于进行主函数中数据的输入。

    在psvm(public static void main)中,需定义一个Solution类的实例solution,并调用对应的方法twoSum,以实现类中方法在主函数中的调用。这样定义实例,可以省去对twoSum方法添加/删除static,以便直接粘贴至leetcode网站中提交。


2. C++:

    在LeetCode中使用C++,不能将C++当成简单的面相过程编程语言而使用,必须要使用面向对象的类/方法设计思路。

    废话少说,上代码:

代码块
C++
自动换行
复制代码
#include <bits/stdc++.h>

//避免使用using namespace std;语句,养成良好的编程习惯。

class Solution {
public:
    std::vector<int> twoSum(std::vector<int>& nums, int target) 
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            for (int j = i + 1; j < n; ++j) {
                if (nums[i] + nums[j] == target) {
                    return {i, j};
                }
            }
        }
        return {};
    }
};

int main() {
    int n; 
  	std::cin >> n;
    std::vector<int> nums;
    for (int i = 0; i < n; i++) 
		std::cin >> nums[i];
    int target; 
  	std::cin >> target;
  
    Solution mySolution;	//创建Solution类的实例mySolution
  
    /* 函数返回值是int 可直接输出 */
    
    //cout << solution.twoSum(nums, target) << endl; *//
    
    /*函数返回值是vector,不可用cout直接输出 */
    
    std::vector<int> res =  mySolution.twoSum(nums, target);
    for (int re : res) {
        std::cout << re << " ";
    }
    
    /*若为双层vector,则需如此定义及输出 */
    
    int N = 5, M = 6;
    std::vector<std::vector<int> > obj(N, std::vector<int>(M));
    for (auto & i : obj)
    {
        for (int j : i)
        {
            std::cout << j << " ";
        }
        std::cout << "\n";
    }
}

复制成功

此代码包含多种输出的方法,读者可以借鉴。


3.python:

    对于python,可以仿效C++语言进行使用。

    由于python也是面相对象编程语言,故也需在main中定义Solution的实例Sol,然后调用实例的方法twoSum进行编程。

代码块
Python
自动换行
复制代码
from typing import List


class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i, j]

        return []


if __name__ == "__main__":
    nums = [2, 7, 11, 15]
    target = 9
    sol = Solution()
    print(sol.twoSum(nums, target))

复制成功

    其中本地测试数据需要在主函数中进行输入,无需在命令行中输入。


结语:

    本篇专栏所写的写题基本方法,一定不是最好的,但是是传统OJ转向LeetCode的好过渡。up主本人也在学习各种更加方便的LeetCode本地编辑策略,希望各位看官如果有好的想法的话,在评论区友好讨论。

    感谢各位的支持!


20240421更新:

    好多同学在后台进行C语言的催更,最近没那么忙了,所以来更新一下C语言的部分:

    C语言是一种典型的面向过程编程语言,是典型的函数式编程语言。所以按照平时的编程习惯,编写一个twoSum函数即可。

    *注意:由于C语言的实参调用为实参的一个拷贝,故如需改变函数中调用的实参的值,应传递该实参的指针(例:swap(int a, int b)  并不能实际调换变量a,b的值,只有当定义为swap(int &a, int &b)时,才能真正改变变量a,b的值。)。

代码块
clike
自动换行
复制代码
int* twoSum(int* nums, int numsSize, int target, int* returnSize) {
    for (int i = 0; i < numsSize; ++i) {
        for (int j = i + 1; j < numsSize; ++j) {
            if (nums[i] + nums[j] == target) {
                int* ret = malloc(sizeof(int) * 2);
                ret[0] = i, ret[1] = j;
                *returnSize = 2;
                return ret;
            }
        }
    }
    *returnSize = 0;
    return NULL;
}
复制成功

update:更新了Java,C++,Python语言对Solution类的调用方法,以免进行方法中static的增删。