leetcode刷题记录---2019.9.9 电话号码组合组合数组解决,字符串数组Z变换to_string(x),全排列(背诵回溯法求排列树难),折半查找解决搜索旋转排序数组(背异或和返回条件)

概述

1.电话号码的字母组合,  这题其实是更新一个vector数组,输入有多长更新几次,每次erase后,len会改变。

2.Z字形变换,只要关注当前行,和前进的方向(即数组的下标,何时该往哪个数组里append)

3.整数反转,自己做出来的,整数转字符串,逆序,再用stringstream做,判断是否溢出

4.删除链表中倒数第N个节点,自己做出来的,双指针,考虑两种特殊情况,1只有一个节点。2要删的是头节点

5.全排列,这题比较难想,给一个数组,使用回溯法求排列树,以交换代替压栈存储。回溯函数三参数(数据集,结果,当前层)

6.搜索旋转排序数组。这题关键是二分查找和异或操作,返回值也比较精简!

 

 

1.电话号码的字母组合

题目描述:如同9宫格键盘一样,数字2-9有分别代表着不同的字母,给定一个只包括数字2-9的字符串,返回可能组成的不同的字符串组合。

参考:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/4ms-83mb-c-by-macrecry/

思路:

1.把9个数字所表示的字符传放入vector容器

2.定义结果存放容器c,

往里面压入"",

c为[""]

第一次遍历后c中元素为["","a","b","c"],                 第一次erase后为["a","b","c"]

第二次遍历后c中元素为["a","b","c","ad","ae"...]     第二次erase后为[...]

详情看代码:len表示前一次处理好的字符串的个数,

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        vector<string> a{ "abc","def","ghi","jkl","mno","pqrs","tuv","wxyz" };
        vector<string> c;
        if (digits.empty()) return c;
        c.push_back("");
        for (int i = 0; i < digits.size(); ++i) {
            int res = digits[i] - '2';
            int len = c.size();
            cout << "len is :" << len << endl;
            for (int j = 0; j < len; ++j) {           //遍历前一次对应的字符
                for (auto m : a[res]) {                //遍历当前按键所对应的字符
                    c.push_back(c[j] + m);              //压入c
                }
            }
            c.erase(c.begin(), c.begin() + len);        //c是数组先存放空格,第二次存放首个数字代表的几个字母,第三次存放第二个数字代表的字符基于前一次,每次都要擦除前一次(相当于中间过程)的数据
        }
        return c;
    }
};

 

2.Z字形变换

题目描述:

给一个字符串和一个行数,把字符串以从上往下、从左到右Z字形排列。返回按行序返回。

示例 1:

输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"
示例 2:

输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:

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

思路:本题核心就是一个容器,存放n个字符串,根据移动的方向,往对应的容器中压字符就可以了。

1.定义rows容器,存放字符。rows是一个有min(numRow,s.size())个元素的字符串数组容器

2.定义当前行和方向,curRow,goingDown

3.遍历s,当前行的字符存入rows,如果当前行为第0行,或者最后一行,方向改变。

   如果方向向下,当前行加一,否则减一

class Solution {
public:
    string convert(string s, int numRows) {
        if(1 == numRows){return s;}
        vector<string>temp(min(int(s.size()),numRows));
        int curRow  = 0;
        bool goingdown = false;
        for(char c:s){
            temp[curRow] += c;
            if(curRow == 0|| curRow == numRows-1)
                goingdown = !goingdown;
            curRow += goingdown ? 1:-1;
            
        }
        string ret = "";
        for(auto ch:temp){ret += ch;}
        return ret;
    }
};

3.整数反转,自己写出来 的

题目描述:给定一个有符号整数,反转他。120反转后21,等反转后如果超过32位系统的int类型范围,则返回0;

思路:

1.先把x转化成字符串

2.反转这个字符串,因为reverse()不是solution的成员函数,所以不能用。。。因此用swap依次交换,交换前把符号提出

____后面莫名其妙又可以用reverse直接反转,真奇怪!std::reverse(s.begin(),s.end())

3.使用stringstream把反转后的字符串转化为int,并判断是否溢出

class Solution {
public:
    
    int reverse(int x) {
        string s = "";               
        s += to_string(x);                
        cout<<s<<endl;
        if(s[0] == '+'||s[0] =='-'){
            int i = 1;
            int k = s.size()-1;
            while(i<k){swap(s[i++],s[k--]);}
        }else{
        //reverse(s.begin(),s.end());
        int i = 0;
        int k = s.size()-1;
        while(i<k){swap(s[i++],s[k--]);}
        cout<<s<<endl;
        }
        stringstream ss;
        ss<<s;
        int res;
        ss>>res;
        cout<<int(pow(2,31)-1)<<endl;
        if(res<-int(pow(2,31))||res>int(pow(2,31))-1) return 0;
        return res;
        
    }
};

4.删除链表的倒数第N个节点,自己A出来

题目描述:给定一个链表和一个数字,删除倒数第n个节点,尝试用一趟扫描实现。

思路:双指针。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* p = head;
        ListNode* q = head;
        if(n == 1 && head->next == nullptr){return nullptr;}
        //ListNode* k = head;
        int k = n;
        while(k&&p->next){p = p->next;k--;}
        if(k == 1){
            head = head->next;
            return head;
        }
        while(p->next){
            p = p->next;
            q = q->next;
        }
        ListNode* temp = q->next;
        q->next = temp->next;
        delete temp;
        return head;
    }
};

5.全排列(比较难想)

给定一个没有重复数字的数组,返回他所有可能的全排列

参考:https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-c-by-she-wo-qi-shui/

思路:用回溯法解决。回溯法求排列树

1.把回溯核心分离出来,backtrack(vector<int>&nums,vector<vector<int>>&res,int i),回溯函数参数一般有三个,一个放数据集,一个放结果,一个表示当前层级

2.如果数组为空,那就压入res

3.遍历数组(从i开始),交换nums[i]和nums[j]

4.递归处理,backtrack(nums,res,i+1)

5.再次交换,这一步在正常的回溯算法中一般是s.pop_back(),回溯到上一步,在此地同样作用,交换回到上一种状态

class Solution {
public:
    void backtrack(vector<int> &nums,vector<vector<int>>&res,int i){
        if(nums.size() == i) res.push_back(nums); // 如果i已经和数组一样长,表示这一种组合方式结束
        for(int j = i;j<nums.size();++j){
            swap(nums[i],nums[j]);
            backtrack(nums,res,i+1);
            swap(nums[i],nums[j]);
        }
    } 
    void swap(int& a,int& b){
        int temp = a;
        a = b;
        b = temp;
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int>>res;
        backtrack(nums,res,0);
        return res;
        
    }
};

6.搜索旋转排序数组

题目描述:给定一个旋转数组,和一个查找目标,logn查找,如果找到返回位置,找不到返回-1

参考:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/ji-jian-solution-by-lukelee/

思路:折半查找,用异或解决简直无敌

1.定义数组开头和结尾的指针

2.二分查找,注意循环结束的条件不带等号

3.定义mid,

4.核心,三个条件异或,(开头元素大于目标)^(开头元素大于中间元素)^(目标大于中间元素)

                  0^0 is 0         0^1 is 1              1^1 is 0                  1^0 is 1

5.返回位置,return start == end&&target == nums[start] ? start:-1;

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //折半查找
        int start = 0;
        int end = nums.size()-1;
        while(start<end){
            int mid = (start+end)>>1;
            if((nums[start]>nums[mid])^(nums[start]>target)^(target>nums[mid])) start = mid+1;
            else end = mid;
        }
        return start==end&&target == nums[start] ? start:-1;
    }
};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值