动态数组和字符串常见的题型

vector的一些常规操作

#include <iostream>

int main() {
    // 1. initialize
    vector<int> v0;
    vector<int> v1(5, 0);
    // 2. make a copy
    vector<int> v2(v1.begin(), v1.end());
    vector<int> v3(v2);
    // 2. cast an array to a vector
    int a[5] = {0, 1, 2, 3, 4};
    vector<int> v4(a, *(&a + 1));
    // 3. get length
    cout << "The size of v4 is: " << v4.size() << endl;
    // 4. access element
    cout << "The first element in v4 is: " << v4[0] << endl;
    // 5. iterate the vector
    cout << "[Version 1] The contents of v4 are:";
    for (int i = 0; i < v4.size(); ++i) {
        cout << " " << v4[i];
    }
    cout << endl;
    cout << "[Version 2] The contents of v4 are:";
    for (int& item : v4) {
        cout << " " << item;
    }
    cout << endl;
    cout << "[Version 3] The contents of v4 are:";
    for (auto item = v4.begin(); item != v4.end(); ++item) {
        cout << " " << *item;
    }
    cout << endl;
    // 6. modify element
    v4[0] = 5;
    // 7. sort
    sort(v4.begin(), v4.end());
    // 8. add new element at the end of the vector
    v4.push_back(-1);
    // 9. delete the last element
    v4.pop_back();
}

Q:寻找数组索引的轴点

Input: 
nums = [1, 7, 3, 6, 5, 6]
Output: 3
Explanation: 
The sum of the numbers to the left of index 3 (nums[3] = 6) is equal to the sum of numbers to the right of index 3.
Also, 3 is the first index where this occurs.

A:思路见注释

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int sum = 0;
        int lSum = 0;
        for(int item : nums) sum += item;//范围for语句求整个vector的和
        for(int j = 0; j<nums.size();++j)
        {
            if(lSum == sum - nums[j] - lSum) return j;
            lSum += nums[j];/在确定的索引j上,保证lSum始终是正确的
        }
        return -1;
        
    }
};

Q:求数组中比其余数大两倍的的最大数,存在返回数组索引,不存在返回-1

A:思路遍历数组,找到最大数m记其索引maxIndex;再次遍历数组,条件(x != m && m < 2*x)为真,则返回-1;否则返回maxIndex

class Solution {
public:
    int dominantIndex(vector<int>& nums) {
        //int m = nums[0];
        int maxIndex = 0;
        for(int i = 1;i<nums.size();++i)
        {
            if(nums[i] > nums[maxIndex])
            {
                //m = nums[i];
                maxIndex = i;
            }
        }
        for(int j = 0;j<nums.size();++j)
        {
            if(j !=  maxIndex && nums[ maxIndex] < 2*nums[j])
                return -1;
        }
        return maxIndex;
    }
};

Q:数组从零开始储存一个数的高位,给这个数加1,求得到的数组

A:

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
        int n = digits.size();
	for (int i = n - 1; i >= 0; --i)
	{
		if (digits[i] == 9)
		{
			digits[i] = 0;
		}
		else
		{
			digits[i]++;
			return digits;
		}
	}
		digits[0] =1;
		digits.push_back(0);
        return digits;
    }
};

思路差不多,贴一个很骚的代码,有助于深刻理解for语句,以及后++、后--

class Solution {
public:
    vector<int> plusOne(vector<int>& digits) {
      for (int i=digits.size(); i--; digits[i] = 0)
        if (digits[i]++ < 9)
            return digits;
    digits[0]++;
    digits.push_back(0);
    return digits;
    }
};

二维数组,C++实现代码

#include <iostream>

template <size_t n, size_t m>
void printArray(int (&a)[n][m]) {
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {
    cout << "Example I:" << endl;
    int a[2][5];
    printArray(a);
    cout << "Example II:" << endl;
    int b[2][5] = {{1, 2, 3}};
    printArray(b);
    cout << "Example III:"<< endl;
    int c[][5] = {1, 2, 3, 4, 5, 6, 7};
    printArray(c);
    cout << "Example IV:" << endl;
    int d[][5] = {{1, 2, 3, 4}, {5, 6}, {7}};
    printArray(d);
}

Q:将一个矩阵按对角线遍历

A:思路找到按对角线输出的元素的横纵坐标之间的关系(但要注意他们的顺序)。PS:最好理解的方法,可惜超时了。。。

vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        if(matrix.empty()) return {};
        
        const int N = matrix.size();
        const int M = matrix[0].size();
        
        vector<int> res;
        for(int s = 0; s <= N + M - 2; ++s)
        {
            // for all i + j = s
            for(int x = 0; x <= s; ++x) 
            {
                int i = x;
                int j = s - i;
                if(s % 2 == 0) swap(i, j);

                if(i >= N || j >= M) continue;
                
                res.push_back(matrix[i][j]);
            }
        }
        
        return res;
    }

改进过的代码(这逻辑好难理解哦,快哭了)PS:这样的代码不可取

class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        int m=matrix.size();
        if (m==0) return res;
        int n=matrix[0].size(), i=0, j=0, inc=-1, count=0;
        
        while (count < m*n) {
            while (i < m && j < n && i >= 0 && j >= 0) {
                res.push_back(matrix[i][j]);
                i+=inc;
                j-=inc;
                count++;
            }
            
            inc*=-1;
            if (inc==1) {
                i++;
                if (j == n) { 
                    i++;
                    j--;
                }
            }
            else {
                j++;
                if (i == m) {
                    j++;
                    i--;
                }
            } 
        }
        
        return res;
    }
};

另一种思路:将每一列从上到下的依次存入vector中,然后再根据列数的奇、偶反转得到最后的结果

class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& matrix) {
        int m = matrix.size();
        if (m == 0) return vector<int>();
        int n = matrix[0].size();
        vector<vector<int>> tmp (m+n-1);
        for (int i = 0; i < m+n-1 ; i++) {
            int row = max(0, i-n+1);
            int col = min(i, n-1);
            for (; col >= 0 && row < m; row++, col--) {
                tmp[i].push_back(matrix[row][col]);
            }
        }
        vector<int> res;
        for (int i = 0; i< tmp.size(); i++) {
            if (i % 2) res.insert(res.end(), tmp[i].begin(), tmp[i].end());
            else res.insert(res.end(), tmp[i].rbegin(), tmp[i].rend());
        }
        return res;
    }
};

Q:旋转打印矩阵

A:思路找到水平移动和竖直移动的规律,得到最终的结果。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
    vector<vector<int> > dirs{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    vector<int> res;
    int nr = matrix.size();     if (nr == 0) return res;
    int nc = matrix[0].size();  if (nc == 0) return res;
    
    vector<int> nSteps{nc, nr-1};
    
    int iDir = 0;   // index of direction.
    int ir = 0, ic = -1;    // initial position
    while (nSteps[iDir%2]) {
        for (int i = 0; i < nSteps[iDir%2]; ++i) {
            ir += dirs[iDir][0]; ic += dirs[iDir][1];
            res.push_back(matrix[ir][ic]);
        }
        nSteps[iDir%2]--;
        iDir = (iDir + 1) % 4;
    }
    return res;
    }
};

设置一个和原矩阵大小相同的布尔矩阵(用来标识是否来过),然后根据条件遍历(向右、向下、向左、向上)操作,直到到下一个合法的元素。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        if(matrix.size() == 0) return res;
        int row = matrix.size(),col = matrix[0].size();
        vector<vector<bool> >seen(row,vector<bool>(col,false));
        int dr[] = {0,1,0,-1};
        int dc[] = {1,0,-1,0};
        int r =0,c=0,di=0;
        for(int i=0;i<row*col;++i)
        {
            res.push_back(matrix[r][c]);
            seen[r][c] = true;
            int cr = r+dr[di];
            int cc = c+dc[di];
            if(0 <= cr && cr < row && 0 <= cc && cc < col && !seen[cr][cc])
            {
                r = cr;
                c = cc; 
            }
            else {
                di = (di + 1) % 4;
                r += dr[di];
                c += dc[di];
            }
        }
        return res;
        }
};

Q:帕斯卡三角形,输入n,则产生n行的帕斯卡三角形,返回的是二维vector

A:思路每行的第一个和最后一个都是1,中间的元素=左上元素+正上元素

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> r(numRows);

        for (int i = 0; i < numRows; i++) {
            r[i].resize(i + 1);
            r[i][0] = r[i][i] = 1;
  
            for (int j = 1; j < i; j++)
                r[i][j] = r[i - 1][j - 1] + r[i - 1][j];
        }
        
        return r;
    }
    
};

Q:给出两个2进制字符串,求它们的和也返回一个字符串

Input: a = "1010", b = "1011"
Output: "10101"

A:思路(因为是二进制,所以进位/2)取出相加字符串中的每一位(-‘0’)转化成数字做运算,得到每一位上的结果在转换为字符。

class Solution {
public:
    string addBinary(string a, string b) {
        string s ="";
        int c = 0,i=a.size()-1, j =b.size()-1;
        while(i >=0 || j>=0 || c==1)
        {
            c += i >= 0 ?a[i--]-'0':0;
            c += j >= 0 ?b[j--]-'0':0;
            s = char(c % 2 +'0') +s;
            c = c>>1;
        }
        return s;
  }
};

Q:返回文本中,第一次次出现字符串字串的位置,不存在的话返回-1

A:思路暴力求解,在文本串中,一个一个的找字串。PS:此题还可以用KMP字符串匹配算法解决

class Solution {
public:
    int strStr(string haystack, string needle) {
        int m = haystack.size(), n = needle.size();
        for (int i = 0; i <= m - n; i++) {
            int j = 0;
            for (; j < n; j++) {
                if (haystack[i + j] != needle[j]) {
                    break;
                }
            }
            if (j == n) {
                return i;
            }
        }
        return -1;
    }
};

Q:字符串数组中,最长的公共子串

A:将第一个字符串的每一个字符都和数组中的所有字符串对应位置比较,如都满足才把字符加入公共字串。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string prefix="";
        if(strs.size()==0)  return prefix;
        
        /** check char by char, for each char, check all the string word **/
        for(int k=0; k<strs[0].size(); k++){
            int i=1;
            for(; i<strs.size() && strs[i].size()>k; i++){
                if(strs[i][k]!=strs[0][k])
                    return prefix;
            }
            if(i==strs.size()) prefix+=strs[0][k];
        }
        return prefix;
    }
};

Q:反转字符数组

A:思路用STL中的reverse方法

class Solution {
public:
    void reverseString(vector<char>& s) {
        reverse(s.begin(), s.end());
    }
};

用两个指针的方法交换首尾对应位置的元素,利用后加加运算。

class Solution {
public:
    void reverseString(vector<char>& s) {
       int i = 0, j = s.size()-1;
        while(i<j)
        {
            int tmp = s[i];
            s[i++] = s[j];
            s[j--] = tmp;  
        }
    }
};

Q:给一个有2n个元素的数组,将其两两分成n对,将每一对求min,然后相加,求这个和的最大值。

A:思路,先用sort()排序,然后将偶数位(下标从零开始)都加起来即得到最后的结果。

class Solution {
public:
    int arrayPairSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int i = 0,sum = 0;
        while(i<nums.size())
        {
            sum += nums[i];
            i += 2;
        }
        return sum;
    }
};

Q:两数之和,输入的数组已经排好序

A:用两个指针从首尾分别开始移动,看是否符合题目的要求

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
         int lo=0, hi=numbers.size()-1;
         while (numbers[lo]+numbers[hi]!=target){
         if (numbers[lo]+numbers[hi]<target){
            lo++;
             } 
        else {
            hi--;
            }
        }
        return vector<int>({lo+1,hi+1});
    }
};

双指针的使用技巧之二--同时有一个快慢指针

code:

int removeElement(vector<int>& nums, int val) {
    int k = 0;
    for (int i = 0; i < nums.size(); ++i) {
        if (nums[i] != val) {
            nums[k] = nums[i];
            ++k;
        }
    }
    return k;
}

Q:移除数组的元素

A:思路遍历数组,如果不等于给定的值那么从头存入,相等的元素直接被后面的元素覆盖掉。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int k = 0;
        for (int i = 0; i < nums.size(); ++i) {
        if (nums[i] != val) {
            nums[k] = nums[i];
            ++k;
        }
    }
    return k;
    }
};

思路遍历数组,把相等的值换到数组尾部。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int first = 0,last = nums.size()-1;
        while(first <= last)
        {
            if(nums[first] == val)
            {
                //swap(nums[first], nums[last]);
                nums[first] = nums[last];
                --last;
            }
            else ++first;  
        }
        return first;
    }
};

Q:数组中的是一串二进制数,求该数组中连续1个数最大是少

A:思路遍历数组,遇到1,++count,遇到0,将累计的结果放入set中并将count清零,循环出来还要插入count(处理最后一个不是0的情况)PS:用set是不是多此一举???(真的是多此一举哦!!!)

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int i = 0,count = 0;
        set<int>ans;
        while(i < nums.size())
        {
            if(nums[i] == 1)
            {
                ++count;
                ++i;
            }
            else
            {
                ans.insert(count);
                count = 0;
                ++i;
            }
        }
        ans.insert(count);
        return *--ans.end();
        }
};

我的改进:

class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int i = 0,count = 0,maxCount = 0;
        //set<int>ans;
        while(i < nums.size())
        {
            if(nums[i] == 1)
            {
                ++count;
                ++i;
            }
            else
            {
                //ans.insert(count);
                maxCount = max(count,maxCount);
                count = 0;
                ++i;
            }
        }
        //ans.insert(count);
        maxCount = max(count,maxCount);
        return  maxCount;
        }
};

大神的简练code:

int findMaxConsecutiveOnes(vector<int>& nums) {
        int max_cnt = 0, cnt = 0;
        for (auto n : nums) {
            if (n == 1) max_cnt = max(++cnt, max_cnt);
            else cnt = 0;
        }
        return max_cnt;
    }

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

A:思路

  • 三个for循环的暴力解法,当sum>=s时,更新最优子数组然后break(找到了以i 开头的符合条件并且最短的子数组)
  • 对求和的过程优化,用一个向量保存数组之前累加的和,这样方便求出任意区间的和
  • 对找到一个j的过程优化,用二分查找的办法
  • 到目前为止,我们一直固定子数组的起始索引,并找到最后一个位置。 取而代之的是,一旦知道使用该索引作为起始索引并不能做得更好,就可以移动当前子数组的起始索引。 我们可以保留2个指针,一个指向当前子数组的开始,另一个指向当前子数组的结尾,并进行最佳移动,以使 sum大于s并保持尽可能小的大小。

贴一个最巧妙的解法:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int i = 0,sum = 0,left = 0;
        int ans = INT_MAX;
        while(i < nums.size())
        {
            sum += nums[i];
            while(sum >= s)//这里是个循环,退出条件是sum < s。用if的话就只能判断一次
            {
                ans = min(ans, i+1-left);
                sum -=nums[left++]; 
            }
            i++;
        }
        return ans !=INT_MAX?ans:0 ;
    }
};

Q:旋转数组

A:这个题的思路比较多,首先利用数学上的规律向右移动即((i+k)%size)。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
       vector<int> ans(nums.size(),0);
        for(int i = 0; i<nums.size();++i)
        {
            ans[(i+k) % nums.size()] = nums[i];
        }
        for(int i =0;i<nums.size();++i)
        {
            nums[i] = ans[i];
        }
    }
};

首先反转整个数组,然后分别反转数组的前k个部分,反转剩下的部分

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        k %= nums.size();
        reverse(nums.begin(),nums.end());
        reverse(nums.begin(),nums.begin()+k);
        reverse(nums.begin()+k,nums.end());
    }
};

PS:最基本的解法就是一个一个的旋转数组,旋转k次。(常规解法超时就不贴代码了)

Q:帕斯卡三角形2

A:和一的解法一样可以解决

class Solution {
public:
    vector<int> getRow(int rowIndex) {
        vector<vector<int>>r(rowIndex+1);
        for(int i = 0;i<rowIndex+1;i++)
        {
            r[i].resize(i+1);
            r[i][0] = r[i][i] = 1;
            for(int j=1;j<i;++j )
                r[i][j] = r[i-1][j-1]+r[i-1][j];
        }
        return r[rowIndex];//vector的下标从零开始
    }
};

大神解法:

class Solution {
public:
    vector<int> getRow(int rowIndex) {
        vector<int> A(rowIndex+1, 0);
        A[0] = 1;
        for(int i=1; i<rowIndex+1; i++)
            for(int j=i; j>=1; j--)
                A[j] += A[j-1];
        return A;
    }
};

Q:将数组中的0放到末尾,不改变非0元素的相对顺序

A:遍历数组,将非0元素覆盖到数组前面,不够数组的个数用0补全。PS:自己的解法。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        //vector<int> ans(nums.size(),0);
        int k=0;
        for(int i = 0;i<nums.size();++i)
        {
            if(nums[i] != 0)
            {
                nums[k] = nums[i];
                ++k;
            }
        }
        while(k<nums.size())
        {
             nums[k++] = 0;
        }
    }
};

最强解法:用两个指针,慢指针之前都是非0元素,在满指针和快指针之间都是0元素。

void moveZeroes(vector<int>& nums) {
    for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
        if (nums[cur] != 0) {
            swap(nums[lastNonZeroFoundAt++], nums[cur]);
        }
    }
}

Q:从排序数组中,删除重复的元素

A:思路利用set来去重。PS:C++之耻,太慢了。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        set<int> ans;
        int i = 0;
        for(int i = 0;i<nums.size();++i)
        {
            ans.insert(nums[i]);
        }
        set<int>::iterator it;
        for(it=ans.begin();it!=ans.end();it++)
        {
           
            nums[i++] = *it;
        }
        return i;
    }
};

用双指针(快慢指针的方法)来解决

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

Q:反转字符串中的单词,其没有额外的空格(#557)

A:用双指针法得到一个单词之后用reverse算法来反转。

class Solution {
public:
    string reverseWords(string s) {
        int fast=0,slow  = 0;
        for(int i = 0;i<s.size();++i)
        {
            if(s[i] != ' ')
                ++fast;
            else
            {
                reverse(s.begin()+slow,s.begin()+fast);
                slow = fast+1;
                ++fast;
            }    
        }
        reverse(s.begin()+slow,s.begin()+fast);
        return s;
    }
};

Q:反转字符串中单词的顺序(#151)

A:分类讨论输入字符的情况:1.为空2.全为空格3.正常的字符串。利用istringstream来处理空格,并将得到的string放入stack中,输出string 直到栈为空,最后去掉多余的空格,处理完毕。PS:空间复杂度高,待优化。

class Solution {
public:
    string reverseWords(string s) {
        int flag = 0;
        for(auto ch:s)
        {
            if(ch != ' ')
            {
                flag = 1;
                break;
            }
            
        }
        if(s.empty()) return s;
        if(!flag) return "";
        stack<string> str_stack;
        istringstream is(s);
        string str;
        while(is >> str)
        {
            str_stack.push(str);
        }
        s.clear();
        while(!str_stack.empty())
        {
            s += str_stack.top();
            s +=" ";
            str_stack.pop();
        }
        s.pop_back();
        return s;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值