刷题likou

本文详细介绍了LeetCode上的一系列经典编程题目,涵盖数组、哈希表、字符串、链表、回文、整数反转等多个主题,通过实例解析算法实现和优化策略,旨在帮助读者提高编程能力和算法理解。
摘要由CSDN通过智能技术生成

目录

第一题---返回最大差值(258)

第二题----俩数之和

第三题---俩数相加

第四题----无重复字符的最长字串

第五题-----最长回文字串

第六题-z型变换

第七题:整数反转

第八题-字符串转换

9回文数

10,乘最多水的容器

12,整数反转罗马数字

13.罗马数字转整数

14.最长公共前缀

15.三数之和

16.最接近的三数之和

17.电话号码的字母组合(很牛逼的方法)--回溯算法

19.删除链表的倒数第n节点

20.有效的括号 

31.下一个排列



第一题---返回最大差值(258)

给你一个下标从 0 开始的整数数组 nums ,该数组的大小为 n ,请你计算 nums[j] - nums[i] 能求得的 最大差值 ,其中 0 <= i < j < n 且 nums[i] < nums[j] 。

返回 最大差值 。如果不存在满足要求的 i 和 j ,返回 -1 。

vector<int>& nums------vector指代的是一维数组

  1. vector<int> nums;//不指定长度

  2. vector<int> nums(n); // 指定长度为

添加元素:nums.push_back(1);//直接从数组末端添加

删除元素

  1. nums.resize(nums.size-i); //直接将数组长度减小,某种方式上删掉了后面i个

  2. nums.pop_back();//删掉最后一个元素

其他 
获得长度:nums.size() 
排序(O(nlogn)):sort(nums.begin(),nums.end()); 
翻转:reverse(nums.begin(), nums.end()); 
合并两个vector:合并nums1和nums2,并将合并后的数组赋值给nums

class Solution {
public:
    int maximumDifference(vector<int>& nums) {
//设置一个vector的一维数组,取名为nums
        int n = nums.size();//定义初始化数组的长度
        int ans = -1, premin = nums[0];//设置一个最小值,以及最小的差值是多少
        for (int i = 1; i < n; ++i) {//从下一位开始进行遍历
            if (nums[i] > premin) {//数组中的下一位值大于最小值的时候
                ans = max(ans, nums[i] - premin);//比较这个值与最小值的差值比较,并且是否更新
            } else {
                premin = nums[i];//如果下一位的值比最小值要小的话,更新最小值
            }
        }
        return ans;
    }
};

第二题----俩数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

(1)第一种思路就是比较简单,俩层遍历直接找到最先找到的

class Solution {
public:
    vector<int> twoSum(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(target==nums[i]+nums[j]){
                    return {i,j};
                }      
            }
        }
        return {};
    }

};

(2)

注意到方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高。因此,我们需要一种更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出它的索引。

使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N)O(N) 降低到 O(1)O(1)。

这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> hashtable;// unordered_map  ---map容器为无序定义
        for (int i = 0; i < nums.size(); ++i) {
            auto it = hashtable.find(target - nums[i]);//auto---类似于一个推到的作用,自动判别出是什么样的类型,并且返回的是一个迭代器的类型
//当开始的时候,寻找map容器中的对应关系,并没有合适的对应关系,此时find返回的是容器的最后一位,并且执行相应的后续位置,if跳过,并且在map中添加对应的键值对

            if (it != hashtable.end()) {it跟最后一个不一样的时候
                return {it->second, i};//返回他的值
            }
            hashtable[nums[i]] = i;//讲map中的值转向下一项
        }
        return {};
    }
};

第三题---俩数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode * header=nullptr,*p_ptr=nullptr;
    int carry=0;
   
    while(l1||l2){
        int n1=l1?l1->val:0;
        int n2=l2?l2->val:0;
        int sum=n1+n2+carry;
        if(!header){
            p_ptr=header=new ListNode(sum%10);
        }else{
           p_ptr->next= new ListNode(sum%10);
           p_ptr=p_ptr->next;
        }
        carry=sum/10;
        if(l1){
            l1=l1->next;
        }
        if(l2){
            l2=l2->next;
        }
    }
    if(carry!=0){
         p_ptr->next= new ListNode(carry);
    }
        return header;
    }
};

第四题----无重复字符的最长字串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

不断地刷新i的位置,当rk在occ当中找不到对应的值时候,不断的增加,直到找到一个一样的为止。

对于i来说,他是不断增加的,就导致一直在向右移,当rk储存一组完全不一样的字符串的时候,i会不断略过,并且清楚rk中储存的字符串,相当于一种窗口移动,使i指向rk中字符串遇到的第一个相同的,作为一个新的起始位置,之后在移动rk的位置,在继续寻找差值最大的那一组字符串

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
 // 哈希集合,记录每个字符是否出现过
        unordered_set<char> occ;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int i = 0; i < n; ++i) {
            if (i != 0) {
                // 左指针向右移动一格,移除一个字符
                occ.erase(s[i - 1]);
            }
            while (rk + 1 < n && !occ.count(s[rk + 1])) {
                // 不断地移动右指针
                occ.insert(s[rk + 1]);
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1);
        }
        return ans;

    }
};

第五题-----最长回文字串

给你一个字符串 s,找到 s 中最长的回文子串。

在这里主要是用的寻找一个中间数的方法,找到一个数不断向外扩张

首先的是选用一个数的进行扩张,找到的都是类似于ada,a这种奇数字节的

然后再用偶数字节进行扩张去寻找,aa,adda这种类型的,进行比较,然后放入设定的start以及end中进行保存,并且不断循环判断,更新start,end的值,并且返回,利用字符串的substr进行字符串中的截取

class Solution {
public:
    pair<int, int> expandAroundCenter(const string& s, int left, int right) {
        while (left >= 0 && right < s.size() && s[left] == s[right]) {
            --left;
            ++right;
        }
        return {left + 1, right - 1};
    }

    string longestPalindrome(string s) {
        int start = 0, end = 0;
        for (int i = 0; i < s.size(); ++i) {
            auto [left1, right1] = expandAroundCenter(s, i, i);
            auto [left2, right2] = expandAroundCenter(s, i, i + 1);
            if (right1 - left1 > end - start) {
                start = left1;
                end = right1;
            }
            if (right2 - left2 > end - start) {
                start = left2;
                end = right2;
            }
        }
        return s.substr(start, end - start + 1);
    }
};

第六题-z型变换

、将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:

思路:::_____________________________________

做完看了下其他人的答案,感觉大部分人都把这道题搞得有点复杂了。
这道题可以这么考虑:对于输入的字符串s,其下标 i / (numRows-1) 如果为偶数或零,则代表该下标代表的字符在Z字型中属于竖列。如果 i / (numRows-1) 如果为奇数,则代表该下标代表的字符在Z字型中属于斜列(Z字型的中间倾斜部分)。
如果当前字符属于竖列,则按照正序依次保存在字符串数组 temp 中(temp[remain].push_back(s[i])),如果属于斜列,则逆序保存(temp[numRows-remain-1].push_back(s[i]))。
最后将 temp 数组依次按序输出就是最终答案。

class Solution {
public:
    string convert(string s, int numRows) {
        vector<string> temp(numRows);
        string res;
        if(s.empty() || numRows < 1) return res;
        if(numRows == 1) return s;
        for(int i = 0; i < s.size(); i++){
            int ans = i / (numRows-1);
            int remain = i % (numRows-1);
            if(ans % 2 == 0){                           //结果为偶数或0
                temp[remain].push_back(s[i]);              //按余数正序保存
            }
            if(ans % 2 != 0){                           //结果为奇数
                temp[numRows-remain-1].push_back(s[i]);    //按余数倒序保存
            }
        }
       for(int i = 0; i < temp.size(); i++){
               res += temp[i];
        }
        return res;
    }
};

第七题:整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−2^{\31},  2^{\31} − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值