LeetCode 解题笔记总

Posted 火山上的企鹅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 解题笔记总相关的知识,希望对你有一定的参考价值。

文章目录

系列篇:     

LeetCode 解题笔记(二)数组篇



● 建议:

1、不会的,没有头绪的,先学习答案,有些方法你脑海中都没有,如何又能想到呢?先学习答案吧
2、暴力解法也是解,先出答案再考虑时间复杂度和空间复杂度
3、选择题目,除了在难度上要循序渐进,还建议在算法上进行划分。目前先刷个100题再说
4、同一类型,批量答题,将有助于系统性的学习!

● 刷题记录

03月09日 更新


一、常用技巧

● 字符串长度或大小:

s.length();
s.size();

● 反转一个数的技巧

resverdNum = resverdNum *10 + x%10;
x/= 10;

● 指针对应的空位 nullptr

if(digits.empty()) return vector<string>();

● ++写在前面

++i:

● range-based for

string s1 =  "123456";
for (auto i : s1 )  	 //普通方式改变访问
   i ++;           		 //改变字符串的每个字符, 不会改变整个字符串s1(123456)
for(const auto& i : s3)  //常引用方式访问元素,避免拷贝代价 s1(123456)
// i ++;                 //报错
for (auto& i : s2 )      //引用方式访问元素
   i ++;                 //改变字符串的每个字符, 使用引用会改变整个字符串s1(234567)

● vector 相关,(代替数组)

int maxArea(vector<int>& height)  int n = height.size()  //取大小
vector<int> vret;			//用于返回最终结果vret
vret.push_back(3);   		//在vret中数组最后插入3
vert.pop_back();			//在vret中最后去掉一个数

vector<int> v(201, 0);		//用于存储nums数组中元素的重复次数
vector<int> b(2,-1);        //初始化一个大小为2,值为-1的容器b

void threeSum(vector<int>& nums) 
	vector<vector<int>> ans;                    //二维数组
	ans.push_back( nums[i], nums[j], nums[k]; //二维数组添加
...


//没有指定 vector 的大小,不能在中间直接插入数据的!

● 普通数组

//初始化
int[] array= new int[5];

● 直接调用函数:交换、快速排序

swap(x,y);                           //值交换直接调用

void fun(vector<int>& nums) 
	std::sort(nums.begin(), nums,end())    //快速排序
	...

● 无穷大的数

int inf = 1e9;              //1e9 表示一个大数,记为无穷大

● map、unordered_map、set、unordered_set

其中 unordered_map、unordered_set 用的太多了!

参考:map,unordered_map,set和unordered_set

● map

优点:有序性,这是map结构最大的优点(map 内部实现了一个 红黑树)

缺点:空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率(低于unorder_map),但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间(但占用的内存比unorder_map低)

适用处:对于那些数据存储有顺序要求的问题,用map会更高效一些

实例:

vector<int> list =  5,14,34,22,39,5;
map<int, int> map;
for (int i = list.size() - 1; i >= 0; i--) 
	map[i] = list[i];  				                   //倒序插入

for (auto num = map.begin(); num  != map.end(); num ++) 
	cout << num->first << ' ' << num->second << endl;  //输出的数是有序的且有两个
	//打印:
	//0 5
	//1 14
	//2 34
	//3 22
	//4 39
	//5 5


//find()和count()的输入参数都是key值
cout << map.find(3)->first << "," << map.find(3)->second;  //3,22

//m.count(n)计算下标为n的位置有无数据,有返回1,无返回0
cout << map.count(5);                                       //  1

参考:https://blog.csdn.net/bryant_zhang/article/details/111600209

● unordered_map(无序的映射 )

优点: 因为内部实现了哈希表,因此,其元素的排列顺序是无序的。因此其查找速度非常的快(运行效率快于map),时间复杂度可达到O(1),其在海量数据处理中有着广泛应用

缺点: 哈希表的建立比较耗费时间(unorder_map占用的内存比map要高)

适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用 unordered_map

vector<int> list =  5,14,34,22,39,5;
unordered_map<int, int> map;
for (int i = list.size()-1; i>=0; i--) 
	map[i] = list[i];                    //倒序插入

for (unordered_map<int, int>::iterator i = map.begin(); i != map.end(); i++)  //auto 更好
	cout << i->first << ' ' << i->second << endl;  //输出的数是有序的且有两个
    /*打印:unordered_map 是基于hash表的,因此元素是无序存储的( 不按键 升序排列)。
	5 5
	4 39
	3 22
	2 34
	1 14
	0 5
	*/


//find()和count()的输入参数都是key值
cout << map.find(3)->first << "," << map.find(3)->second;  //3,22

//m.count(n)计算下标为n的位置有无数据,有返回1,无返回0
cout << map.count(5);                                       //  1

//删除下标为 5 的位置
cout << map.erase(5);   

实例2:

leetcode :169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

class Solution 
public:
    int majorityElement(vector<int>& nums) 
        //哈希, 不用数组因为是不知道有多大;对于乱序问题、查找问题,适用于 unordered_map
        unordered_map<int,int> seen;
        int n = nums.size();
        int majority = 0;
        for(auto const & num : nums) 
            seen[num]++;
            if(seen[num] > n/2) 
                majority = num;
            
        
        return majority;
    
;

实例3: 17. 电话号码的字母组合

unordered_map<char, string> phoneMap
    '2', "abc",
    '3', "def",
    '4', "ghi",
    '5', "jkl",
    '6', "mno",
    '7', "pqrs",
    '8', "tuv",
    '9', "wxyz"
;

● set

set 实现了红黑树的平衡二叉检索树的数据结构,插入元素时,它会自动调整二叉树的排列,把元素放到适当的位置,以保证每个子树根节点键值大于左子树所有节点的键值,小于右子树所有节点的键值;另外,还得保证根节点左子树的高度与右子树高度相等。**在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。**平衡二叉检索树使用中序遍历算法,检索效率高于vector、deque和list等容器,另外使用中序遍历可将键值按照从小到大遍历出来。

实例1

vector<int> list =  5,14,34,22,39,5 ;
set<int> set1;
for (int i = list.size() - 1; i >= 0; i--) 
	set1.insert(list[i]);  //倒序插入

for (auto num = set1.begin(); num  != set1.end(); num ++) 
	cout << *num << endl;  //输出的数是有序的且只有一个5
	/*打印结果* set 是基于RBT的,因此元素是顺序存储的(默认按 键值 升序排列)。
	5
	14
	22
	34
	39 */

cout << *set1.find(5) << endl;   //5
cout <<  set1.count(5) << endl;  //1

● STL 容器: unordered_set

unordered_set的内部实现了一个 哈希表,因此, 其元素的排列顺序是无序的。

实例1:

//#include <unordered_set>
vector<int> list =  5,14,34,22,39,5 ;
unordered_set<int> set;
for (int i = list.size() - 1; i >= 0; i--) 
	set.insert(list[i]);  //倒序插入

for (unordered_set<int>::iterator num = set.begin(); num  != set.end(); num ++) 
	cout << *num  << endl;  //输出的数是无序的且只有一个5
	/*打印结果: unordered_set是基于hash表的,因此元素是无序存储的( 不按键值 升序排列)。
	5
	39
	14
	22
	34 */

cout <<  *set.find(39) << endl;  //39
cout <<   set.count(14) << endl;  //1

实例2:

//初始化一个结构体
unordered_set<ListNode *> seen;
//判断是否包含某一个元素
seen.count(head);
//添加一个元素
seen.insert(head);

实例三: 217.存在重复元素

class Solution 
public:
    bool containsDuplicate(vector<int>& nums) 
        unordered_set<int> s;
        for (int x: nums) 
            if (s.find(x) != s.end()) 
                return true;
            
            s.insert(x);
        
        return false;
    
;

二 、常用翻译

revertedNum   //回收的数
merge // 合并
frequency   //频率

三、题目


x. 其他

9. 回文数–2021/12/09

链接9. 回文数
标签
思路:1. 字符串反转;2. 数字的反转(采用这个),且只需要反转一半,当然奇数需要多反转一下。
注意:1. 特殊数的判定:位数为0的、数字0、负数 2. 奇数和偶数的判定 3.while和for的抉择

class Solution 
public:
    bool isPalindrome(int x) 
        //负数不考虑,末尾为0不考虑
        //0 的特殊性
        if(x<0 || (x%10==0 && x!=0) ) 
            return false;
        

        int revertedNum = 0;

        while(revertedNum < x) 
            revertedNum = revertedNum * 10 + x%10;
            x /= 10;
        
        return (x==revertedNum) || (x==revertedNum/10);    
    
;

11. 盛最多水的容器–2022/01/05

链接: 11. 盛最多水的容器

题目:

关键词: 双指针

暴力解法:(会超时)

class Solution 
public:
    int maxArea(vector<int>& height) 
        int n = height.size();
        int maxarea = 0;
        for(int i=1; i<n; i++) 
            for(int j=0; j<i; j++) 
                maxarea = max(min(height[j], height[i]) * (i-j), maxarea);
            
        
        return maxarea;
    
;

官方答案: 双指针

抛弃长的,以短的边,水只会越来越少。所以只能抛弃短的,以长的为边,水才有可能越来越大~,人生也是如此,知道已经是最差的活法呢,为什么不换一种方式重新开始呢!

class Solution 
public:
    int maxArea(vector<int>& height) 
        int left=0, right=height.size()-1;
        int water = 0;

        while(left < right) 
            int tmp = min(height[left] ,height[right]) * (right - left) ;
            water = max(tmp, water);
            if(height[left] < height[right]) 
                ++ left;
            
            else 
                -- right; 
            
        
        return water;
    
;

15. 三数之和–2022/01/14

链接:15. 三数之和

标签: 双指针、排序、数组

我的思路: 三重循环,但是没有考虑重复的,比如 -5,1,1,1,4,4,4 就有多组重复的

思路: 排序+双指针, 排序后,然后固定第一个数,另外两个数从两头加,大了话,右指针减,小了话左指针加,知道 left=right ,然后再去重!

网友简洁版答案:(好理解)

class Solution 
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
        int n = nums.size();
        vector<vector<int>> ret;
        if(n < 3)  return ;            // 特判
        //快速排序
        std::sort(nums.begin(), nums.end());
        //固定第一个数,转化为求两数之和
        for(int i=0; i<n; ++i)         
            if(nums[i] >0)  return ret;         //第一个数为0,后续也不可能相加为0了,除开0,0,0
            if(i>0 && nums[i] == nums[i-1])  continue;
            int left = i+1, right =n-1;          // 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
            while(left < right) 
                if(nums[left] + nums[right] > -nums[i]) 
                    --right;                      // 两数之和太大,右指针左移
                
                else if(nums[left] + nums[right] < -nums[i]) 
                    ++left;                       // 两数之和太小,左指针右移
                
                else 
                     // 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
                    ret.push_back( nums[i], nums[left], nums[right] );
                    --right;
                    ++left;
                    // 去重:第二个数和第三个数也不重复选取
                    //  例如: -5,1,1,1,4,4,4  如果用if还是会重复 -5 1 4, 要用while
                    while (left < right && nums以上是关于LeetCode 解题笔记总的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题笔记-数据结构-day4

LeetCode刷题笔记-数据结构-day4

LeetCode Convert Sorted Array to Binary Search Tree

LeetCode刷题笔记-动态规划-day3

LeetCode刷题笔记-动态规划-day3

LeetCode刷题笔记-动态规划-day3