• Leetcode数组类算法题1


    1.

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

    你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

    示例:

    给定 nums = [2, 7, 11, 15], target = 9

    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

    使用count,返回的是被查找元素的个数。如果有,返回1;否则,返回0。注意,map中不存在相同元素,所以返回值只能是1或0。

    使用find,返回的是被查找元素的位置,没有则返回map.end()。

    //方法二:hashmap
    //关联容器是对容器概念的一个改进,将值与键关联在一起
    //可以降低一重时间复杂度
    
    class Solution {
    public:
        vector<int> twoSum(vector<int>& nums, int target) 
        {
            unordered_map<int,int>m;
            vector<int>res;
            for (int i=0;i<nums.size();i++)
            {
                m[nums[i]]=i;
            }
            for (int j=0;j<nums.size();j++)
            {
                int t = target- nums[j];
                if (m.count(t) && m[t]!=j){//判断的先后顺序一定不能弄错了
                    res.push_back(j);
                    res.push_back(m[t]);
                    break;
                }
                    
                
            }
            return res;
        }
    }; 

    11.

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

    说明:你不能倾斜容器,且 n 的值至少为 2。

     

    图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

    示例:

    输入: [1,8,6,2,5,4,8,3,7]
    输出: 49

     //因为要求最大面积,所以游标从两边一起卡

    class Solution {
    public:
        //这个时间复杂度只有O(n)
        //使用while循环,一定要找准那个让循环增加或者减少的那个点,非常重要。
        //using namespace std;
        int maxArea(vector<int>& height)
        {
            int max = 0, i = 0, j = height.size() - 1;
            while (i < j)
            {
                max = std::max(max,std::min(height[i],height[j]) * (j - i));
                if (height[i] < height[j])
                    i++;
                else
                    j--;
            }
            return max;
        
        }
            
    };
    //这种方法复杂度太大了,尽管结果通过了,能不暴力写就不要这样写
    /*
        int maxArea(vector<int>& height) 
        {
            int sum = 0;int sum1,sum2;
            for (int i=0;i<height.size();i++)
            {
                for(int j=i+1;j<height.size();j++)
                {
                    sum1 = (j-i)*height[i];
                    sum2 = (j-i)*height[j];
                    if (height[j]>=height[i]&&sum1>=sum)
                        sum = sum1;
                    else if (height[j]<height[i])
                    {
                        if (sum2>sum)
                            sum = sum2;
                    }
                
                }
                
            }
            return sum;
        }*/

    15.

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

    注意:答案中不可以包含重复的三元组。

    例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

    满足要求的三元组集合为:
    [
    [-1, 0, 1],
    [-1, -1, 2]
    ]

    1.将数组排序

    2.定义三个指针,i,j,k。遍历i,那么这个问题就可以转化为在i之后的数组中寻找nums[j]+nums[k]=-nums[i]这个问题,也就将三数之和问题转变为二数之和---(可以使用双指针)

    //不能借鉴two sum的HashMap方法,就算用set去除重复也不好处理!

    Python版本:

    class Solution:
        def threeSum(self, nums: List[int]) -> List[List[int]]:
            nums.sort()
            res =[]
            i = 0
            for i in range(len(nums)):
                if i == 0 or nums[i]>nums[i-1]:
                    l = i+1
                    r = len(nums)-1
                    while l < r:
                        s = nums[i] + nums[l] +nums[r]
                        if s ==0:
                            res.append([nums[i],nums[l],nums[r]])
                            l +=1
                            r -=1
                            while l < r and nums[l] == nums[l-1]:
                                l += 1
                            while r > l and nums[r] == nums[r+1]:
                                r -= 1
                        elif s>0:
                            r -=1
                        else :
                            l +=1
            return res

    C++版本1:(暴力计算肯定是超时的)

    用双指针的方法

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> three; 
    vector<int>num; if (nums.size() >=3) { sort(nums.begin(), nums.end()); int first, last; for (int i = 0; i < nums.size() - 2; i++)//这是一个剪枝的过程,对第一个游标进行处理 { if (i>0 && nums[i] == nums[i - 1])
    //后面这个判断是必须的,为什么呢?因为同样的数字只能处理一次!(当不需要两个数字同时用的时候)删掉会变成[[-1,-1,2],[-1,0,1],[-1,0,1]]
    continue; first = i + 1; last = nums.size() - 1; int sum; while (first != last)//用first和last两边游标同时逼近是减少时间复杂度的利器 { sum = nums[i] + nums[first] + nums[last]; if (sum < 0) first++; if (sum > 0) last--; if (sum == 0) { if (nums[first] != nums[first - 1]||first==i+1) { num.push_back(nums[i]); num.push_back(nums[first]); num.push_back(nums[last]); three.push_back(num); num.clear();//这一步非常重要! } first++; } } } } return three; } };

    C++版本2:(有部分实例通不过,比如000的情况,继续思考)这种方法是模仿的two sum的方法!

    //暴力计算的方法肯定是超时的!
    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) 
        {
            vector<vector<int>>m;
            unordered_map<int,int> p;
            //至少要一重循环的
            //vector<int>nums1=sort(nums);
            sort(nums.begin(),nums.end());
            if (nums.size()>=3){
                for (int i=0;i<nums.size();i++)
                {
                    p[nums[i]]=i;
                }
            
                for (int i=0;i<nums.size()-2;i++)
                {
                    if (i>0 && nums[i] == nums[i - 1]) 
                        continue;        
                    p[nums[i]]=i;
                    vector<int>res;
                    //这个前后可能有重复的,我怎么判断呢?
                    for(int j=i+1;j<nums.size()-1;j++)
                    {
                        p[nums[j]]=j;
                        int t = -nums[i]-nums[j];
                    //因为有两个-1,这个判断时候优先判断的是前面的一个
                    //if(p[t]<j) 
                        if (p.count(t) && p[t]>i && p[t]>j)
                        {
                            res.push_back(nums[i]);res.push_back(nums[j]);res.push_back(t);
                        //break;
                            m.push_back(res);
                            res.clear();
                        }
                     //m.push_back(res);
                    }
                }
            }
            return m;
        }
    };

    26.删除排序数组中的重复项

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

    不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

    示例 1:

    给定数组 nums = [1,1,2],

    函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

    你不需要考虑数组中超出新长度后面的元素。
    示例 2:

    给定 nums = [0,0,1,1,1,2,2,3,3,4],

    函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。

    你不需要考虑数组中超出新长度后面的元素。
    说明:

    为什么返回数值是整数,但输出的答案是数组呢?

    请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

    你可以想象内部操作如下:

    // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
    int len = removeDuplicates(nums);

    // 在函数里修改输入数组对于调用者是可见的。
    // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
    for (int i = 0; i < len; i++) {
        print(nums[i]);
    }

    C++方法1:(这种方法没有原地修改数组)

    class Solution {
    public:
        int removeDuplicates(vector<int>& nums) {
            vector<int>nums1;
            int len = nums.size();
            //nums1[0] = nums[0];
            //if (nums != NULL)
            if(nums.size()==0){
                return 0;
            }
            nums1.push_back(nums[0]);
            for (int i=1;i<len;i++)
            {
                if(nums[i]!=nums[i-1])
                    nums1.push_back(nums[i]);
            }
            nums = nums1;
            
            return nums.size();
              
            
        }
    };

    C++方法2:(空间开销比前面一种小)

    //用C++双指针的方法
    class Solution {
    public:
        int removeDuplicates(vector<int>& nums) {
            int i=0,j=0;
            while(j<nums.size())
            {
                int tmp = nums[j];
                nums[i++] = nums[j++];//是相等过之后i和j分别+1
                while(j<nums.size() && tmp == nums[j])
                    j++;
            }
            return i; 
            
        }
    };

    35. 搜索插入位置

    给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

    你可以假设数组中无重复元素。

    示例 1:

    输入: [1,3,5,6], 5
    输出: 2
    示例 2:

    输入: [1,3,5,6], 2
    输出: 1
    示例 3:

    输入: [1,3,5,6], 7
    输出: 4
    示例 4:

    输入: [1,3,5,6], 0
    输出: 0

    Python版本:(二分法查找)

    class Solution(object):
        def searchInsert(self, nums, target):        
            low = 0
            high = len(nums)
            while low < high:
                mid = low + (high - low)/2
                if nums[mid] > target:
                    high = mid
                elif nums[mid] < target:
                    low = mid +1
                else:
                    return mid
            return low

    C++版本1:(这种题目非常简单)

    class Solution {
    public:
        int searchInsert(vector<int>& nums, int target) {
            ////这个数组本来就排好序了
            for(int i=0;i<nums.size();i++)
            {
                if(target==nums[i])
                    return i;
                else if (target<nums[i])
                    return i;
                //else 
                   // return nums.size();
                else if (target>nums[nums.size()-1])
                    return nums.size();
            }
            return 0;
        }
    };

    C++版本2:(可以用lower_bound函数)

    class Solution {
    public:
        int searchInsert(vector<int>& nums, int target) {
            int position = lower_bound(nums.begin(),nums.end(),target)-nums.begin();
            return position;
        }
    };

     C++版本3:常规方法----二分法

    class Solution {
    public:
        int searchInsert(vector<int>& nums, int target) {
            int low = 0, high = nums.size();//二分法的high最好比最后一个数值位数大一个
            int mid;
            while(low<high)
            {
                mid = low+(high-low)/2;
                if (nums[mid]>target)
                    high = mid;
                else if (nums[mid]<target)
                    low = mid + 1;
                else
                    return mid;
            }
            return low;
        }
    };

    53. 最大子序和

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

    输入: [-2,1,-3,4,-1,2,1,-5,4],
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
    进阶:

    如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

    //要考虑全部是负数的情况

    Python解法:

    class Solution(object):
        def maxSubArray(self, nums):
            """
            :type nums: List[int]
            :rtype: int
             """
            for i in range(1, len(nums)):
                nums[i]= nums[i] + max(nums[i-1], 0)
            return max(nums)

    C++解法一:(只要遍历两次)

    class Solution {
    public:
        //找到一个具有最大和的连续子数组
        int maxSubArray(vector<int>& nums) 
        {
            int ans=0;
            int max=0;
            //这个负数的情况在这个函数里应该怎么处理?
            //if(max(nums)<0)
              //  return std::max(nums);
    //考虑全部是负数的情况 int max1=INT_MIN;//应该是数组的最小范围了 for(int i=0;i<nums.size();i++){ max1 = std::max(max1,nums[i]); } if (max1<0) return max1; for(int i=0;i<nums.size();i++) { ans+=nums[i]; if (ans<=0) ans=0; if (ans>max) max = ans; } return max; } };

    C++解法二:(动态规划)

    这道题根据题目关键词,“最大”“连续”,可以判断是一道动态规划,附上这道题目的wiki链接https://zh.wikipedia.org/wiki/%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E5%88%97%E9%97%AE%E9%A2%98 方法如下:

    1. 定义一个函数f(n),以第n个数为结束点的子数列的最大和,存在一个递推关系f(n) = max(f(n-1) + A[n], A[n]);
    2. 将这些最大和保存下来后,取最大的那个就是,最大子数组和。因为最大连续子数组 等价于 最大的以n个数为结束点的子数列和 附代码
    class Solution {
    public:
        int maxSubArray(vector<int>& nums) {
            if(nums.size() == 0) return NULL;
            int res = INT_MIN;
            int f_n = -1;
            for(int i = 0; i < nums.size(); ++i){
                f_n = max(nums[i], f_n + nums[i]);
                res = max(f_n, res);
            }
            return res;
        }
    };

    66. 加一

    给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。

    最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。

    你可以假设除了整数 0 之外,这个整数不会以零开头。

    示例 1:

    输入: [1,2,3]
    输出: [1,2,4]
    解释: 输入数组表示数字 123。
    示例 2:

    输入: [4,3,2,1]
    输出: [4,3,2,2]
    解释: 输入数组表示数字 4321。

     Python解法一:

    (python 先通过list恢复成一个数 然后加1 再恢复成一个list)

    class Solution(object):
        def plusOne(self, digits):
            """
            :type digits: List[int]
            :rtype: List[int]
            """
            value = 0
            length = len(digits)
            for i in range(length):
                value += digits[length-i-1]*pow(10,i)
            value1 = value+1
            res=[]
            while (value1 != 0):
                p = value1%10
                value1 = value1/10
                res.append(p)
            return list(reversed(res))

    Python解法二:

    class Solution(object):
        def plusOne(self, digits):
            """
            :type digits: List[int]
            :rtype: List[int]
            """
            return map(int, str(int(''.join(map(str,digits))) + 1))

    C++ 解法:(活用insert函数)

    class Solution {
    public:
        vector<int> plusOne(vector<int>& digits) {
            int carry = 1;
            for(int i = digits.size() - 1 ; i >= 0; i--){
                int tmp = (digits[i] + carry) % 10;
                carry = (digits[i] + carry)/10;
                digits[i] = tmp;
                if(carry == 0)//因为这样,前面就不要动了,可以节省运行时间
                    break;
            }
            //这是判断最前面一个数字的情况
            if(carry != 0)
                digits.insert(digits.begin(),1);  
            return digits;
            
        }
    };

    88.合并两个有序数组

    给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

    说明:

    初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
    你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
    示例:

    输入:
    nums1 = [1,2,3,0,0,0], m = 3
    nums2 = [2,5,6], n = 3

    输出: [1,2,2,3,5,6]

    (非常经典、常规的解法)

    class Solution {
    public:
        void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) 
        {
            int i1 = m - 1, i2 = n - 1;
          while(i1 >= 0 && i2 >= 0) 
          {
            if(nums1[i1] > nums2[i2]) {
                nums1[i1 + i2 + 1] = nums1[i1];
                i1--;
            }
            else 
            {    
                nums1[i1 + i2 + 1] = nums2[i2];
                i2--;
            }
         }
            //如果是i1的话,多下来的话,直接用,位置不变
        while(i2 >= 0) {
            nums1[i1 + i2 + 1] = nums2[i2];
            i2--;
        }
            
            
        }
    };

    118. 杨辉三角

    给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

    在杨辉三角中,每个数是它左上方和右上方的数的和。

    示例:

    输入: 5
    输出:
    [
    [1],
    [1,1],
    [1,2,1],
    [1,3,3,1],
    [1,4,6,4,1]
    ]

    Python解法:

    def generate(self, numRows):
            """
            :type numRows: int
            :rtype: List[List[int]]
            """
            result = []
            for i in range(numRows):
                now = [1]*(i+1)
                if i >= 2:
                    for n in range(1,i):
                        now[n] = pre[n-1]+pre[n]
                result += [now]
                pre = now
            return result

    C++ 解法:

    如果单纯只是输出结果,确实不复杂,两个循环加上一个递归方法就能解决问题,代码也很优雅。但是提交的时候却没有通过,提示执行超时,显示的测试用例是输入数为30。仔细阅读了代码之后,做了2轮优化。1,递归是非常消耗资源的,仔细观察杨辉三角为对称结构,因此只需要递归其中一半的数据就可以,另外一半通过循环直接赋值;2,再仔细观察发现每一行的第二个和倒数第二个值为行数的值减一,这个特殊的地方可以直接返回计算值,而不需要递归计算,减少性能消耗。两次优化之后,终于提交成功

    class Solution {//速度非常快,非常常规的思路!
    public:
    
        vector<vector<int>> generate(int numRows) 
        {
            vector<vector<int>> vec(numRows); //相当于动态内存分配,相当于有numRows这么多的vector<int>结构
            if(!numRows) 
           return vec; vec[0].push_back(1); if(numRows==1) return vec; vec[1].push_back(1); vec[1].push_back(1); if(numRows==2) return vec; for(int i=2;i!=numRows;++i) { vec[i].push_back(1); for(int j=0;j!=i-1;++j) {
             vec[i].push_back(vec[i
    -1][j]+vec[i-1][j+1]);
           } vec[i].push_back(
    1); } return vec; } };

    119. 杨辉三角II

    给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

    在杨辉三角中,每个数是它左上方和右上方的数的和。

    示例:

    输入: 3
    输出: [1,3,3,1]
    进阶:

    你可以优化你的算法到 O(k) 空间复杂度吗?

    //当执行代码vector<int> v(2,5)时,在内存里建立了2个整形元素空间,值是5.

    //assgin功能:将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector容器中以前的内容

    C++ 解法1:(没有看懂)

    class Solution {
    public:
        vector<int> getRow(int rowIndex) {
            vector<int> cur(1,1),pre;
            while(rowIndex--){
                pre.assign(cur.begin(), cur.end());
                cur.push_back(1);
                for(int i=1;i<cur.size()-1;i++)
                    cur[i]=pre[i-1]+pre[i];
            }
            return cur;
        }
    };

     C++解法2:(用到了递归的思想)3=1+1+1 比较难想到

    class Solution {
    public:
        vector<int> getRow(int rowIndex) {
            vector<int> rows(rowIndex + 1,1);//建立了这么多整型空间,值是1       
            for(int i = 0 ; i <= rowIndex; ++i){
                for(int j = i - 1 ; j > 0 ; --j){
                    rows[j] += rows[j-1];
                }
            }
            return rows; 
        }
    };

    121.买卖股票的最佳时机

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

    如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

    注意你不能在买入股票前卖出股票。

    示例 1:

    输入: [7,1,5,3,6,4]
    输出: 5
    解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
    注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
    示例 2:

    输入: [7,6,4,3,1]
    输出: 0
    解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

    动态规划 前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格}

    Python解法:

    class Solution:
        def maxProfit(self, prices):
            """
            :type prices: List[int]
            :rtype: int
            """
            min_p, max_p = 999999, 0
            for i in range(len(prices)):
                min_p = min(min_p, prices[i])
                max_p = max(max_p, prices[i] - min_p)
            return max_p

    C++ 解法:

    (还是经典的dp思路)

    class Solution {
    public:
        int maxProfit(vector <int>& prices) {
    //简单动态规划方法
    //这种不断用到前面结果的题目,用动态规划是一种好的方法
    if(prices.size() <= 1) return 0; int min = prices[0], max = 0; for(int i = 1; i < prices.size(); i++) { max = std::max(max, prices[i] - min); min = std::min(min, prices[i]); } return max; } };

    122. 买卖股票的最佳时机II

    给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

    示例 1:

    输入: [7,1,5,3,6,4]
    输出: 7
    解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
      随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
    示例 2:

    输入: [1,2,3,4,5]
    输出: 4
    解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
      注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
      因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

    示例 3:

    输入: [7,6,4,3,1]

    输出: 0

    解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

    Python解法:

    class Solution(object):
        def maxProfit(self, prices):
            profit = 0
            for day in range(len(prices)-1):
                differ = prices[day+1] - prices[day]
                if differ > 0:
                    profit += differ
            return profit

    C++解法:(这道题目没有那么难,也不要想的太复杂了)

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int res = 0;
            for (int i = 1; i < prices.size(); i++)
                if (prices[i] > prices[i - 1]) 
              res += (prices[i] - prices[i - 1]); return res; } };

    167. 两数之和 II - 输入有序数组

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

    函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

    说明:

    返回的下标值(index1 和 index2)不是从零开始的。
    你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
    示例:

    输入: numbers = [2, 7, 11, 15], target = 9
    输出: [1,2]
    解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

    C++解法:(指针对撞,减少开销)去用left和right比,可以减少一重循环

    /*class Solution {
    public:
        //这个解法时间开销太大了
        vector<int> twoSum(vector<int>& numbers, int target) {
            //int count = 0;
            vector<int>res(2);
            for (int i=0;i<numbers.size();i++)
            {
                for (int j=i+1;j<numbers.size();j++)
                {
                    if(numbers[i]+numbers[j] == target)
                    {
                        //res.push_back(i+1);
                        //res.push_back(j+1);
                        res[0]=i+1;
                        res[1]=j+1;
                        break;
                        //return res;
                        
                    }
                    //break;
                        
                }
            }
            return res;   
        }
    };*/
    //多用while循环,不要条件反射只会用for
    
    //第二种解法属于指针对撞的解法,可以降低时间复杂度,复杂度是O(n)
    //也可以用二分法,时间复杂度也是O(n)
    class Solution {
    public:
        vector<int> twoSum(vector<int>& numbers, int target) 
        {
            vector<int> result;
    
            int left = 0, right = numbers.size() - 1;
            
            while(left < right){
                if(numbers[left] + numbers[right] == target){
                    result.push_back(left + 1);
                    result.push_back(right + 1);
                    break;
                }
                else if(numbers[left] + numbers[right] > target){
                    right--;
                }
                else if(numbers[left] + numbers[right] < target){
                    left++;
                }
            }
            return result;
        }
    };

    169. 求众数

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

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

    示例 1:

    输入: [3,2,3]
    输出: 3
    示例 2:

    输入: [2,2,1,1,1,2,2]
    输出: 2

    从第一个数开始count=1,遇到相同的就加1,遇到不同的就减1,减到0就重新换个数开始计数,总能找到最多的那个

    C++解法1:

    class Solution {
    public:
        int majorityElement(vector<int>& nums) {
            sort(nums.begin(),nums.end());
            int i=0;
            int n=1;
            while(i<nums.size()-1)
            {
                while(i+1<nums.size() && nums[i+1]==nums[i])
                {
                    n++;
                    i++;
                }            
                if(n > (nums.size()/2))
                    return nums[i];           
                n=1;
                i++;             
            }    
            return nums[i];
        }
    };

     C++解法2:(自己写的,比较容易想)

    class Solution {
    public:
        int majorityElement(vector<int>& nums) {
            sort(nums.begin(), nums.end());
            int count = 1;//1 1 1 2 2 2 2 
            int i = 1;
            while(i<nums.size())
            {
                if(nums[i]==nums[i-1])
                {
                    count++;
                    if (count>nums.size()/2)
                        return nums[i];
                }
                else if (nums[i]!=nums[i-1])
                {
                    count=1;
                }
                i++;
            }
            return nums[0];
        }
    };

    209. 长度最小的子数组

    给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组。如果不存在符合条件的连续子数组,返回 0。

    示例: 

    输入: s = 7, nums = [2,3,1,2,4,3]
    输出: 2
    解释: 子数组 [4,3] 是该条件下的长度最小的连续子数组。
    进阶:

    如果你已经完成了O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。

    //这种解法非常好!!
    class Solution {
    public:
        int minSubArrayLen(int s, vector<int>& nums) {
            int start=-1, minlength=nums.size()+1, sum=0;
            for (int i=0;i<nums.size();i++) {
                sum+=nums[i];
                while (sum >= s) {
                    minlength=min(minlength, i-start);
                    start++;
                    sum-=nums[start];               
                }
            }
            return minlength == nums.size()+1 ? 0 : minlength;
        }
    };
    /*
    //这种解法也可以,比较容易理解!!
    class Solution {
    public:
        int minSubArrayLen(int s, vector<int>& nums) {
            int n = nums.size();
            int sum = 0;
            int min = n + 1;
            
            for (int start = 0, end = 0; start < n && end < n;)
            {
                while (sum < s && end < n)
                    sum += nums[end++];
                    
                while (sum >= s && start < n)
                {
                    if (min > (end - start))
                        min = end - start;
                    
                    sum -= nums[start++];
                }
            }
            
            if (min == (n + 1))
                return 0;
            
            return min;
        }
    };*/

    217. 存在重复元素

    给定一个整数数组,判断是否存在重复元素。

    如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

    示例 1:

    输入: [1,2,3,1]
    输出: true
    示例 2:

    输入: [1,2,3,4]
    输出: false
    示例 3:

    输入: [1,1,1,3,3,4,3,2,4,2]
    输出: true

    Python解法:(直接用set)

    class Solution:
        def containsDuplicate(self, nums):
            """
            :type nums: List[int]
            :rtype: bool
            """
            set1 = set(nums)
            if len(set1) == len(nums):
                return False
            else:
                return True

    C++ 解法一:(用map去做,后面的键值存储出现了多少次)

    class Solution {
    public:
        bool containsDuplicate(vector<int>& nums) 
        {
            map<int,int> nums1;//一开始默认的初始值就是0
            for(int i = 0;i<nums.size();i++)
            {
                nums1[nums[i]]++;
                if(nums1[nums[i]] == 2)
                    return true;
            }
            return false;
        }
    };

    C++解法二: (用set去做)

    class Solution
    {
    public:
        bool containsDuplicate(vector<int>& nums)
        {
            set<int> s(nums.begin(),nums.end());
            if(s.size() != nums.size())
                return true;
            return false;
        }
    };

    C++解法三:(最普通直接的解法,但是是最快的)

    class Solution {
    public:
        bool containsDuplicate(vector<int>& nums) 
        {
            if(nums.empty())
                return false;
    //注意判断空的情况 sort(nums.begin(),nums.end());
    for(int i = 0;i<nums.size()-1;i++) { if(nums[i] == nums[i+1]) return true; } return false; } };

    219. 存在重复元素II

    给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k。

    示例 1:

    输入: nums = [1,2,3,1], k = 3
    输出: true
    示例 2:

    输入: nums = [1,0,1,1], k = 1
    输出: true
    示例 3:

    输入: nums = [1,2,3,1,2,3], k = 2
    输出: false

    class Solution {
    public:
        //正常循环判断解法显示堆栈溢出,这是为什么呢?
        bool containsNearbyDuplicate(vector<int>& nums, int k) {
            unordered_map<int,int> m;
            for(int i=0;i<nums.size();i++)
            {
                if(m.count(nums[i]) && i-m[nums[i]]<=k)
                    return true;
                m[nums[i]] = i;
            }
            return false;
        }
    };

    414. 第三大的数

    给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。

    示例 1:

    输入: [3, 2, 1]

    输出: 1

    解释: 第三大的数是 1.
    示例 2:

    输入: [1, 2]

    输出: 2

    解释: 第三大的数不存在, 所以返回最大的数 2 .
    示例 3:

    输入: [2, 2, 3, 1]

    输出: 1

    解释: 注意,要求返回第三大的数,是指第三大且唯一出现的数。
    存在两个值为2的数,它们都排第二。

    Python解法:

    class Solution:
        def thirdMax(self, nums: List[int]) -> int:
            nums = list(set(nums))
            if len(nums) < 3:
                return max(nums)
            
            nums.sort(reverse=True)
            return nums[2]

    C++解法:(用list和set的特性)---速度最好的方法

    class Solution {
    public:
        int thirdMax(vector<int>& nums) {
            int small_fir=nums[0],small_sec=INT_MIN,i=1;
            long res=INT_MIN-1L;
            while(i<nums.size()&&nums[i]==small_fir)
                i++;
            if(i>=nums.size())
                return small_fir;
            small_sec=nums[i];
            if(small_fir<small_sec)
                swap(small_fir,small_sec);
            for(;i<nums.size();i++)
            {
                if(nums[i]<small_sec)
                    res=max((long)nums[i],res);
                else if(nums[i]>small_fir)
                {
                    res=small_sec;
                    small_sec=small_fir;
                    small_fir=nums[i];
                }
                else if(nums[i]<small_fir&&nums[i]>small_sec)
                {
                    res=small_sec;
                    small_sec=nums[i];
                }
            }
            return res==INT_MIN-1L?small_fir:(int)res;
        }
    };

    448. 找到所有数组中消失的数字

    给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

    找到所有在 [1, n] 范围之间没有出现在数组中的数字。

    您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

    示例:

    输入:
    [4,3,2,7,8,2,3,1]

    输出:
    [5,6]

    【笔记】将所有正数作为数组下标,置对应数组值为负值。那么,仍为正数的位置即为(未出现过)消失的数字。

    举个例子:

    • 原始数组:[4,3,2,7,8,2,3,1]

    • 重置后为:[-4,-3,-2,-7,8,2,-3,-1]

    结论:[8,2] 分别对应的index为[5,6](消失的数字)

    class Solution {
    public:
        vector<int> findDisappearedNumbers(vector<int>& nums) 
        {
            
            for (int i = 0; i < nums.size(); ++i)
                nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);
            vector<int> res;
            for (int i = 0; i < nums.size(); ++i){
                if (nums[i] > 0)
                    res.push_back(i+1);
            }
            return res;
        }
    };

     比较容易想,但是有差错,且使用了额外的空间

    class Solution {
    public:
        vector<int> findDisappearedNumbers(vector<int>& nums) 
        {
            sort(nums.begin(),nums.end());
            vector<int>nums1;
            nums1.push_back(nums[0]);
            for(int i=1;i<nums.size();i++)
            {
                if(nums[i]!=nums[i-1])
                    nums1.push_back(nums[i]);
                else 
                    continue;
            }
            vector<int>nums2;
            for(int i=0;i<nums1.size();i++)
            {
                if(nums1[i+1]==nums1[i]+1)
                    continue;
                else if (nums1[i+1]!=nums1[i]+1)
                    //nums2.push_back(nums[i]+1);
                {
                    int num = nums1[i+1]-nums1[i];
                    for(int j=1;j<num;j++)
                    {
                        nums2.push_back(nums1[i]+j);
                    }
                }
                    
            }
            return nums2;
        }
    };
  • 相关阅读:
    8.24Java入门--->第二十六节
    IDEA-->右键没有创建包选项--->新建包不能自动扩展
    8.21Java入门--->第二十五节(多线程)
    个人冲刺(一)——体温上报app(二阶段)
    个人作业——家庭记账本
    个人冲刺(五)——家庭记账本
    个人冲刺(四)——家庭记账本
    个人冲刺(三)——家庭记账本
    个人冲刺(二)——家庭记账本
    个人冲刺(一)——家庭记账本
  • 原文地址:https://www.cnblogs.com/guohaoyu110/p/11038823.html
Copyright © 2020-2023  润新知