LeetCode算法打卡--数组

1. 两数之和

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

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


链接:https://leetcode-cn.com/problems/two-sum

/*基本思想:使用一个哈希表来解,第一遍扫描,保存到哈希表中,第二遍扫,看target-n在不在哈希表中,时间复杂度为O(n)。
  其实就是模拟python的in 查找是否在里面
*/

c++解法

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
      
        map<int, int> mapping;
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i) {
            mapping[nums[i]] = i;
        }
        for (int i = 0; i < nums.size(); i++) {
            int searched = target - nums[i];
            if (mapping.find(searched) != mapping.end() && i != mapping[searched]) {
                res.push_back(i);
                res.push_back(mapping[searched]);
                break;
            }
        }
        return res;

    }
};

python解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        
        index1 = 0
        while index1<len(nums):
            rest = target -  nums[index1]
            
            for i in range(index1+1,len(nums)):
                if nums[i] == rest:
                    index2 = i
                    return index1,index2
        
            index1+=1;
        return []

15. 三数之和

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


链接:https://leetcode-cn.com/problems/3sum


/*基本思想:使用dfs暴力会时间超限,所以思想就是利用双指针,先对数组排序 对于每一个数i,双指针指向i+1和尾,和==0 继续,和<0,l++,和>0,r--
注意=0的时候加入结果需要判断重复,可以使用set去重
特殊情况:全是0的时候也会时间超限,所以可以直接在循环数组的时候,如果i和前一个相同,就不进行操作了
*/
class Solution {
public:

    vector<vector<int>> threeSum(vector<int>& nums) {
       
        vector<vector<int>>res;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i] > 0) break;
            if(i>0 && nums[i]==nums[i-1])       //  第一个数取的时候去重
               continue;
            int left = i+1;
            int right = nums.size()-1;
            while(left<right)
            {
                vector<int>cur;
                int sum = nums[i]+nums[left]+nums[right];
                if(sum==0)
                {
                    cur.push_back(nums[i]);
                    cur.push_back(nums[left]);
                    cur.push_back(nums[right]);

                    if(left==0 || right==nums.size()-1 || (left >0 && nums[left]!=nums[left-1]) ||( right<nums.size()-1 && nums[right] != nums[right+1]))    //去重判断,也可以使用set进行去重
                         res.push_back(cur);              
                      left++;
                      right--;
                }
                else if(sum<0)                    
                      left++;
                else 
                      right--;
            }
        }
      
        return res;
    }
  

  

};

18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。


链接:https://leetcode-cn.com/problems/4sum

/*基本思路:和3sum类似,只是固定两个数,然后用双指针一前一后进行逼近
*/
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        
        vector<vector<int>> res;
        set<vector<int>> s;
       
        if(nums.size()<4)
            return res;
        sort(nums.begin(),nums.end());
        for(int i=0;i<nums.size()-3;i++)
        {
        
           for(int j=i+1;j<nums.size()-2;j++)
            {
                int left = j+1;
                int right = nums.size()-1;
                int sum;
                while(left<right)
                {
                    sum=nums[i]+nums[j]+nums[left]+nums[right];
                    if(sum==target)
                    {
                         vector<int> cur;
                         cur.push_back(nums[i]);
                         cur.push_back(nums[j]);
                         cur.push_back(nums[left]);
                         cur.push_back(nums[right]);
                         s.insert(cur);
                         left++;
                         right--;
                    }
                    else if(sum<target)
                       left++;
                    else
                       right--;
                }

            }
        }
        set<vector<int>>::iterator iter = s.begin();
         for(;iter!=s.end();iter++)
         {
            res.push_back(*iter);
         }
     return res;
    }
};

 

16. 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。


链接:https://leetcode-cn.com/problems/3sum-closest
 

/*
    基本思想:先把数组排序,第一层循环每个数遍历一次,找后面的两个数相加,利用双指针,第二个数从i+1开始 第三个数最后开始,因为数组是有序的,所以如果和比target大,就是离target更近的应该在前面,再向后加差距就更大了 则n3--
    如果比target小,同理则n2++,一样距离为0 返回target,在求出和之后更新cur就是和target距离最近的。
*/

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int n1;
        int n2=0;
        int n3=nums.size()-1;
        int cur = nums[0]+nums[1]+nums[2];
        
        for(n1=0;n1<nums.size();n1++)
        {
            n2=n1+1;
            n3=nums.size()-1;
            while(n2<n3)
            {
                int sum = nums[n1]+nums[n2]+nums[n3];
                if(abs(sum-target) < abs(cur-target))
                    cur = sum;
                if(sum>target)
                    n3--;
                else if(sum<target)
                    n2++;
                else
                    return target;
            }
        }
        return cur;
        
    }
};

 

66. 加一

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

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

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


链接:https://leetcode-cn.com/problems/plus-one

/*基本思想:记录进位就好,最后利用reverse转置
*/
class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        vector<int> res;
        int i=digits.size()-1;
        int rest = 0;
        int curnum;
        curnum = (digits[i]+1)%10;
        rest = (digits[i]+1)/10;
        res.push_back(curnum);
        for(i=digits.size()-2;i>=0;i--)
        {
            curnum = (digits[i]+rest)%10;
            rest = (digits[i]+rest)/10;
            res.push_back(curnum);
        }
        if(rest == 1)
            res.push_back(1);
        reverse(res.begin(),res.end());
        return res;
    }
};

41. 缺失的第一个正数

给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

说明:

你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。

链接:https://leetcode-cn.com/problems/first-missing-positive/

/*基本思想:方法一:数组排序,从1开始找第一个不存在的正整数,时间复杂度为O(nlogn)
           方法二:假设数组长度为n,遍历数组,数组中的值在1-n的范围内的数a放在对应的a-1的位置,如果不在就与在a-1那个位置的数交换,调整之后,遍历数组,如果这个值i所处的位置不是i-1,就返回i+1就是最小的正整数
        遍历完了之后返回n+1.这相当于是数组下标+1表示正整数,存储对应下标的征整数,没有这个值就是最小的正整数,时间复杂度O(n)
*/
class Solution {
public:
   /* int firstMissingPositive(vector<int>& nums) {
        int res=1;
        int i;
        sort(nums.begin(),nums.end());
        for(i=0;i<nums.size();i++)
        {
            if(res==nums[i])
              res++;
          
        }
        return res;
    }*/
    int firstMissingPositive(vector<int>& nums) {
        
        for(int i=0;i<nums.size();i++)
        {
            while(nums[i]<nums.size()&& nums[i]>0  &&nums[i]!=nums[nums[i]-1])
                swap(nums[i],nums[nums[i]-1]);            
        }
        int i;
        for(i=0;i<nums.size();i++)
        {
            if(i+1!=nums[i])
              return i+1;
        }
      return i+1;
    }
};

121. 买卖股票的最佳时机

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

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

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


链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock

/*基本思想:方法一:直接对于每一天买入的情况,在买入的之后的每一天判断收益,收益大的就更新结果
           方法二:贪心,先记录最小值,遍历碰到更小的值就更新,不小的话就计算收益,大的更新结果
*/
class Solution {
public:
    /*int maxProfit(vector<int>& prices) {
        int profit=0;
        int i;
        for(i=0;i<prices.size();i++)
        {
            int j=i+1;
            for(;j<prices.size();j++)
            {
                if(prices[j]-prices[i]>profit)
                    profit = prices[j]-prices[i];
            }
        }
       return profit;
        
    }*/

     int maxProfit(vector<int>& prices) {
        int profit=0;
        if(prices.size()==0)
            return 0;
        int min = prices[0];
        int i;
        for(i=0;i<prices.size();i++)
        {
            if(prices[i]<min)
                min = prices[i];
            else
               profit = max(profit,prices[i]-min);
        } 
        return profit;
    }
};

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

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

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

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


链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii

/*
  基本思想:方法一:保留当前的利润,遍历,min是最小值也是买入的时候,如果遍历比min小,那就从此刻买入,加上前面的利润,重新计算利润,如果比min大,那就判断是否是最大的,计算利润判断就是后面还有没有更大的,如果没有比之前的利润大,就在此刻买入,重新计算
            方法二:直接遍历一次,找连续递增的,连续递增就是利润累加,一次买入,一次卖出,最终利润是多个连续递增的累加和
*/

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

123. 买卖股票的最佳时机 III

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

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

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


链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii

/*基本思想:动态规划,对于第i天来说,考虑前面0-i天的最大收益和后面i-n天的最大收益,两个累加就是第i天的两次交易之后的最大收益,然后在i天中找最大的
          
*/
class Solution {
public:
    int maxProfit(vector<int>& prices) {

        if(prices.size()==0)
           return 0;
        vector<int> dp1(prices.size(),0);  //前面i天中收益最大的,判断是第i天是否卖出,不卖出就是i-1的收益
        vector<int> dp2(prices.size(),0);  //后面i天中收益最大的,判断是第i天是否买入,不买入就是i+1的收益
        int i;
        int minval = prices[0];
       for(i=1;i<prices.size();i++)
       {
           dp1[i] = max(prices[i]-minval,dp1[i-1]);
           if(prices[i]<minval)
              minval = prices[i];
       }

       int maxval = prices[prices.size()-1];
       for(i=prices.size()-2;i>=0;i--)
       {
           dp2[i] = max(maxval-prices[i],dp2[i+1]);
           if(prices[i]>maxval)
              maxval = prices[i];
          
       }
        
        int Profit =0;
        for(i=0;i<prices.size();i++)
        {
            Profit = max(Profit,dp1[i]+dp2[i]);
        }
        return Profit; 
    }
};

27. 移除元素

给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度。

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

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。


链接:https://leetcode-cn.com/problems/remove-element

/*基本思想:
        方法一:用两个下标来记录,j相当于存新的不为val的数,但是在原数组的基础上存储,不额外增加内存,i就遍历数组,找到不为val的存入j的位置。
            最后j就是新的数组的长度
        方法二:针对牛客的输出设置
           设置前后两个游标,pre和last,分别指向数组的前后。
           算法执行开始,先从last游标开始向前执行,每次遇到A[last] = elem时候,将last-1.当A[last] != elem时候,pre再从前边向后执行,
            当A[pre] != elem的时候pre+1,否则将A[pre] = A[last],pre+1且last-1.
*/
class Solution {
public:
     //不改变相对位置
    /*int removeElement(vector<int>& nums, int val) {
        int len = nums.size();
        
        int i=0,j=0;
        while(i<nums.size())
        { 
           
            if(nums[i]!=val)
            {
                nums[j++] = nums[i];
            }
           
            i++;
        }            
        
        
        return j;
    }*/
    
     //改变相对位置,前后指针
    int removeElement(vector<int>& nums, int val) 
    {    
         int pre = 0;   
         int n =nums.size();
         int last = n-1;        
         while( pre <= last)
         {            
             if (nums[last] == val) 
             {                 
                 last--;            
             } 
            else {                 
                 if(nums[pre] != val)
                 {                    
                     pre++;                
                 } 
                 else 
                 {                     
                     nums[pre] = nums[last];                     
                     pre++;                 
                     last--;                
                 }            
             }     
         }         
         return last+1;
      }    
};


88. 合并两个有序数组

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

链接:https://leetcode-cn.com/problems/merge-sorted-array/

/*基本思想:因为要合并到num1数组里面所以从后向前合并填写
*/
class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        int index = m+n-1;
        int i=m-1;
        int j=n-1;
        while(i>=0 && j>=0)
        {
            
            if(nums1[i] <= nums2[j])
            {
                
                nums1[index--] = nums2[j];
                j--;
            }
            else 
            { 
                nums1[index--] = nums1[i];
                i--;
            }
        }
        while(i>=0)
        {
            nums1[index--] = nums1[i--];
           
        }
        while(j>=0)
        {
            nums1[index--] = nums2[j--];
        }
        
    }
};

128. 最长连续序列

给定一个未排序的整数数组,找出最长连续序列的长度。

要求算法的时间复杂度为 O(n)。

示例:

输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。


链接:https://leetcode-cn.com/problems/longest-consecutive-sequence

/*基本思想:用到c++STL中的hash表,hash的查找和删除都是O(1)的时间复杂度,所以满足条件
  只需要对于每一个数,向前找第一个不在数组中的,向后找最后一个不在的,计算比较得到最大的连续长度即可
*/
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
         int res=0;
         unordered_set<int> st(nums.begin(),nums.end());
         for(int i=0;i<nums.size();i++)
         {
             int num = nums[i];
             st.erase(num);
             int befor=num-1;
             int after=num+1;
             while(st.find(befor)!=st.end())
                 st.erase(befor--);
             while(st.find(after)!=st.end())
                 st.erase(after++);    //不删也可以就是检查的数据多了
            
             res = max(res,after-befor-1);
            
         }
        return res;
        
    }
};

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

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

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


链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
 

/*基本思想:双指针i,j都指向数组,然后用i的数赋值在j的位置(和移除某个元素的思想一样)
*/
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
         if(nums.size()==0)
             return 0;
        int i=1,j=1;
        while(i<nums.size())
        {
            if(nums[i]!=nums[i-1])
            {
                nums[j++]=nums[i];
            }
            i++;
        }
        return j;
    }
};

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

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

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


链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii

/*基本思想:还是两个指针,但是i直接和j-2的位置比较,相等就表示已经存在两个了,不等情况下再放入
*/
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if(nums.size()<=2 )
            return nums.size();
        int i=2,j=2;
        while(i<nums.size())
        {
            if(nums[i] != nums[j-2])
                nums[j++] = nums[i];
            i++;
        }
        
        return j;
    }
};


4. 寻找两个有序数组的中位数

链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/submissions/

/*基本思想: 方法一:将两个数组合并,找中位数,但是时间复杂度不符合要求
            方法二:二分查找,转化为找两个有序数组中第k个元素,并且采用二分法搜索第k个元素,每次查找第k/2个元素,对于两个数组,确定每次搜索的范围数组中到底存不存在第K/2个数字,如果存在就取出来,否则就赋值上一个整型最大值。如果某个数组没有第K/2个数字,那么我们就淘汰另一个数字的前K/2个数字即可。有没有可能两个数组都不存在第K/2个数字呢,这道题里是不可能的,因为我们的K不是任意给的,而是给的m+n的中间值,所以必定至少会有一个数组是存在第K/2个数字的。最后就是二分法的核心啦,比较这两个数组的第K/2小的数字midVal1和midVal2的大小,如果第一个数组的第K/2个数字小的话,那么说明第一个数组前k/2个元素在合并之后一定在k之前,一定不是第k个元素,所以我们可以将其淘汰,将nums1的起始位置向后移动K/2个,并且此时的K也自减去K/2,调用递归。反之,我们淘汰nums2中的前K/2个数字,并将nums2的起始位置向后移动K/2个,并且此时的K也自减去K/2,调用递归即可。
*/

class Solution {
public:
   /* double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int i=0,j=0;
        vector<int> res;
        int m=nums1.size();
        int n=nums2.size();
        while(i<nums1.size() && j<nums2.size())
        {
            if(nums1[i] <= nums2[j])
                {res.push_back(nums1[i]);
                  i++;
                }
                else
                {
                    res.push_back(nums2[j]);
                    j++;
                }
        }
        while(i<nums1.size())
        {
            res.push_back(nums1[i]);
            i++;
        }
        while(j<nums2.size())
        {
            res.push_back(nums2[j]);
            j++;
        }
        if((m+n)%2==0)
           return (double)(res[(m+n)/2-1]+res[(m+n)/2])/2;
        else
           return res[(m+n)/2];
    }*/

     int findKth(vector<int>& nums1, int i,vector<int>& nums2 ,int j,int k){

        if( i >= nums1.size()) return nums2[j + k - 1];//nums1为空数组
        if( j >= nums2.size()) return nums1[i + k - 1];//nums2为空数组
        if(k == 1){
            return min(nums1[i], nums2[j]);
        }
        int midVal1 = (i + k / 2 - 1 < nums1.size()) ? nums1[i + k / 2 - 1] : INT_MAX;
        int midVal2 = (j + k / 2 - 1 < nums2.size()) ? nums2[j + k / 2 - 1] : INT_MAX;
        if(midVal1 < midVal2){
            return findKth(nums1, i + k / 2, nums2, j , k - k / 2);
        }else{
            return findKth(nums1, i, nums2, j + k / 2 , k - k / 2);
        } 
     }       
    
    
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    
        int m = nums1.size();
        int n = nums2.size();
        int left = (m + n + 1) / 2;
        int right = (m + n + 2) / 2;
        return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
    
    }

};

945. 使数组唯一的最小增量

给定整数数组 A,每次 move 操作将会选择任意 A[i],并将其递增 1

返回使 A 中的每个值都是唯一的最少操作次数。

链接:https://leetcode-cn.com/problems/minimum-increment-to-make-array-unique/

/*
  基本思路:
     方法一:空间换时间  每个数最大为40000,那么相加最大80000,开辟一个数组,遍历原数组,对应的值放到对应下标的位置,如果放过了,那就线性向后放(向后的次数也就是move的次数)
     方法二: 先排序,每次比较和前一个数的关系,不大,那就赋值为比他大的第一个,move也就是他俩的差加一,统计所有的关系即可
*/

class Solution {
public:
    /*
    int minIncrementForUnique(vector<int>& A) {
        int nums[80000] ;
        memset(nums, -1, 80000*sizeof(int));
        int count = 0;
        for(int i=0;i<A.size();i++)
        {
            int index = A[i];
            if(nums[index] != index)
            {
                nums[index] = index;
            }
            else
            {
                while(nums[index] == index)
                {
                    count++;
                    index++;
                }
                nums[index] = index;
            }
        }
        return count;
    }
    */
    int minIncrementForUnique(vector<int>& A) {
        sort(A.begin(),A.end());
        int count = 0;
        for(int i=1;i<A.size();i++)
        {
           if (A[i] <= A[i-1])
           {
               count+=  A[i-1] - A[i] + 1 ;
               A[i] =A[i-1]+1;
           }
        }
        return count;

    }
};

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

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

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


链接:https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array

/*基本思想: 方法一:把数字都放到自己对应的位置上,如果当前i不满足放在正确位置上,看正确位置是他说明重复,那这个i地方置为-1,表示空,否则就交换到正确位置,满足条件或者本身为-1就继续,最后遍历判断值为-1的位置就是消失的数字
    方法二:  原地哈希,对于每一个出现的数,把他对应的位置置为对应的负数,没有被置为负数就是消失的数字
*/
class Solution {
public:
 vector<int> findDisappearedNumbers(vector<int>& nums) {
      vector<int> res;
      for(int i=0;i<nums.size();i++)
       {
        if(nums[abs(nums[i])-1]>0)
          nums[abs(nums[i])-1] *= -1;  
       }
       for(int i=0;i<nums.size();i++)
       {
           if(nums[i]>0)
             res.push_back(i+1);
             
       }
       return res;
 }
/*
    vector<int> findDisappearedNumbers(vector<int>& nums) {
       vector<int> res;
       int i=0;
       while(i<nums.size())
       {
           if(nums[i]==-1 || nums[i]==i+1 )
           {   i++;
               continue;
           }
           if(nums[nums[i]-1] == nums[i])
           {
               nums[i] = -1;
               i++;
               continue;
           } 
           swap(nums[i], nums[nums[i]-1]);
       }
      
       for(int i=0;i<nums.size();i++)
       {
           if(nums[i] == -1)
               res.push_back(i+1);

       }
       return res;
    }
*/
};

41. 缺失的第一个正数

给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。

链接:https://leetcode-cn.com/problems/first-missing-positive/

/*基本思想:正确的数放到正确的位置,小于0和大于数组长度的数不交换,注意最小正数一定在1-n+1之间 只有在两个数不相等的时候交换才会避免死循环
*/
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int i=0;
        while(i<nums.size())
        {
            if(nums[i] != i+1 && 0<nums[i] && nums[i]<nums.size() && nums[i] != nums[nums[i]-1])
               swap(nums[i],nums[nums[i]-1]);
            else
               i++;

        }
        int res = nums.size()+1;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i] != i+1)
               return i+1;
        }
        return res;
    }
};

442. 数组中重复的数据

给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次

找到所有出现两次的元素。

链接:https://leetcode-cn.com/problems/find-all-duplicates-in-an-array/

/*基本思路: 方法一:对应的数放到正确的位置上,如果不在正确位置,判断正确位置的数正确,则说明重复就作为返回结果,否则就交换,注意有重复的话,就设置一个-1表示这个数已经不需要处理了
            方法二:还是对应位置的数变成负数,然后当前已经是负的说明出现过,保存为结果
*/
class Solution {
public:
/*
    vector<int> findDuplicates(vector<int>& nums) {
        int i=0;
        vector<int> res;
        while(i<nums.size())
        {
            if(nums[i]<0)
            {
                i++;
                continue;
            }
            if(nums[i] != i+1 && nums[i] != nums[nums[i]-1])
            {
                swap(nums[i], nums[nums[i]-1]);
            }
            else if(nums[i] != i+1)
            {
                res.push_back(nums[i]);
                nums[i] = -1;
                i++;
            }
            else
                i++;

        }
        return res;
    }*/
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> res;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[abs(nums[i])-1]<0){
              res.push_back(abs(nums[i]));
            }
            else
              nums[abs(nums[i])-1] *= -1;
            
        }
        return res;
    }
};

219. 存在重复元素 II

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


链接:https://leetcode-cn.com/problems/contains-duplicate-ii

/*基本思想:利用哈希,存储下标就好
*/
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.find(nums[i]) != m.end())
           {
               if(i-m[nums[i]]<=k)
                   return true;
               else
                 m[nums[i]] = i;
           }
           else
             m[nums[i]] = i;
       }
       return false;
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

你的算法时间复杂度必须是 O(log n) 级别。

如果数组中不存在目标值,返回 [-1, -1]。


链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array

/*基本思想:二分查找,找到target然后两边搜索边界
*/
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;
        int start=-1;
        int end=-1;
        vector<int> res;
         while(left<=right)
         {
             cout<<left<<right<<endl;
             int mid = (left+right)/2;
             if(nums[mid] == target)
             {
                  start = mid;
                 while(start>=0 && nums[start]==target)
                     start--;
                  res.push_back(start+1);
                  end = mid;
                 while(end<nums.size() && nums[end]==target)
                     end++;
                  res.push_back(end-1);
                return res;
             }
             else if(nums[mid]<target){
                left=mid+1;
             }
             else
                right = mid-1;
         }
       
        
            res.push_back(start);
      
            res.push_back(end);
    return res;
    }
};

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?


链接:https://leetcode-cn.com/problems/single-number

 

/*基本思路:两种方法:
    方法一: 数组排序,前后相同则跳过继续,不同返回
    方法二:用异或,两数相同异或为0,0和其他数异或为这个数
*/
class Solution {
public:
    /*
    int singleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int i;
        for(i=0;i<nums.size();i++)
        {
            if(i!=nums.size()-1 && nums[i]==nums[i+1])
            {
                i++;
                continue;
            }
            else
                return nums[i];
        }
        return 0;
    }
    */
     int singleNumber(vector<int>& nums)
     {
         
         int res=0;
        for (int i=0;i<nums.size();i++){
            res^=nums[i];
        }
        return res;
     }
};

137. 只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?


链接:https://leetcode-cn.com/problems/single-number-ii

/*
   基本思想:方法一:数组排序,和后两个比较相同跳过,继续,不同返回
            方法二:位操作,int有32位对于每一位统计,如果一个数出现3次,那这一位累计和一定是和3整除,否则取余数就是剩下的那个数,最后得到结果的每一位用或操作统计这个数
*/
class Solution {
public:
    /*
    int singleNumber(vector<int>& nums) {
        
        sort(nums.begin(),nums.end());
        int i;
        for(i=0;i<nums.size();i++)
        {
            if(i!=nums.size()-1 && nums[i]==nums[i+1] && nums[i]==nums[i+2])
            {
                i+=2;
                continue;
            }
            else
                return nums[i];
        }
        return 0;

    }
    */
    int singleNumber(vector<int>& nums) {
        
        int result=0;
         for(int i=0;i<32;i++)
             
         {
             int bits=0;
             for(int j=0;j<nums.size();j++)
             {
                 bits+=(nums[j]>>i)&1;
             }
             result|=(bits%3)<<i;
         }
        return result;
    
    
    }
};

260. 只出现一次的数字 III

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

链接:https://leetcode-cn.com/problems/single-number-iii/


/*
  基本思想:先对所有的数异或,结果就是要找的两个数的异或值,可以从这值找一个非0位,因为只有两个数的该位不一样,结果才为0
  这两个数一定是在这一位一个为0,一个为1,按这个标准将数组划分,这一位为1的和num1异或,为0和num2异或得到这两个数

*/
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        vector<int> result;
        int num1=0,num2=0;
        int res=0;
        for(int i=0;i<nums.size();i++)  //全部异或
        {
            res^=nums[i];
        }
        
        int bit_1 = 1;
        while((res & 1) == 0)    //取最低位第一个非0的位数
        {
            res >>= 1;
            bit_1 <<= 1;
        }
       for(int i=0;i<nums.size();i++)
       {
           if((nums[i] & bit_1)!=0)    //这一位为1的和nums1异或
               num1^=nums[i];
           else
               num2^=nums[i];
       }
        result.push_back(num1);
        result.push_back(num2);
        return result;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值