leetcode 30-39

16 篇文章 0 订阅
12 篇文章 0 订阅

32.Longest Valid Parentheses
思路1:最长有效字符串。用stack存储栈顶的Index,start记录有效字符串开始位置。如果是’(‘,入栈,如果是’)’,判断stack是否为空,如果为空,说明’)’是第一个字符,有效字符串一定不是从这个字符开始的,则start+1;不为空的话,则stack.pop(),如果stack为空,则取res和i - start + 1 的最大值;如果stack不为空,则取res和i - m.top()最大值。

int longestValidParentheses(string s) {
        stack<int> m;
        int res = 0,start = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '(')
                m.push(i);
            else {
                if (m.empty()) start = i + 1;
                else {
                    m.pop();
                    res = m.empty() ? max(res,i - start + 1) : max(res,i - m.top());
                }
            }
        }
        return res;
    }

33.Search in Rotated Sorted Array
思路:首先,观察规律。
这里写图片描述
对于[0,1,2,4,5,6,7],有7种翻转情况。看红色部分,都是有序的;存在一个规律,如果中间数比最后一个数大,则左边是有序子序列,相反,则右边是有序的。运用这个规律,进行code。
二分法。首先,比较nums[mid]和target,如果相等直接返回mid;如果不相等,则判断和最后一个数的大小关系:1.如果中间数大于最后一个数,则说明左边是有序的,然后通过比较target和左边第一个和最后一个大小关系,判断target是否在左边,否则在右边。2.如果中间数小于最后一个数,则说明右边是有序的,然后通过比较target和右边第一个数和最后一个大小关系,判断target是否在右边。

int search(vector<int>& nums, int target) {
        int n = nums.size();
        int left = 0,right = n - 1;
        int mid;
        while (left <= right) {
            mid = (left + right) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] > nums[right]) { //中间数比最后一个数大,则说明前面有序
                if (nums[left] <= target && nums[mid] > target) right = mid - 1;
                else left = mid + 1;
            }
            else {
                if (nums[mid] < target && nums[right] >= target) left = mid + 1;
                else right = mid - 1;
            }
        }
        return -1;
    }

34.Search for a Range
思路:在一个排好序的数组中,找到target的下标。总体思路是先找到左边界,然后再找右边界。

  1. 初始化res=[-1,-1],如果数组为空,则返回[-1,-1];
  2. 定义low记录最左边界,high则是最右边界,left和right是为了操作方便。
  3. 当left < right时,比较nums[middle]和target,如果target大,则说明target在middle右边,所以left = middle + 1,反之,则说明target在middle左边或者就在middle,right = middle;
  4. 可能循环执行结束,没有找到target,判断nums[left]是否等于target,如果不相等,则说明数组中没有target,返回[-1,-1].
  5. 执行到现在,说明有target,那么左边界找到了,就是left,low= left,进行保存左边界。right = n -1,开始找left到最后这一段的右边界。
  6. 当left < right时,nums[middle] == target,说明右边界大于等于middle,所以赋值left = middle + 1(本来赋值left = middle,但是这种情况,会陷入死循环,比如[8,8,10],left会停在第二个8那里);反之nums[middle] > target(注意,这里不可能出现nums[middle] < target),说明右边界小于middle,则right = middle - 1;
  7. 在找右边界的时候,可能出现nums[right] != target,如果不相等就right - 1。
 vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res = {-1,-1};
        int n = nums.size();
        if (n == 0)
            return res;
        int low,high;
        int left = 0,right = n - 1;
        int middle;
        while (left < right) {
            middle = (left + right) / 2;
            if (nums[middle] < target) {
                left = middle + 1;
            }
            else {
                right = middle;
            }
        }

        if (nums[left] != target) {
            return res;
        }
        low = left;
        right = n - 1;
        while (left < right) {
            middle = (left + right) / 2;
            if (nums[middle] == target) {
                left = middle + 1; //如果写left = middle,会陷入死循环
            }
            else {
                right = middle -1 ;
            }
        }
        if (nums[right] != target)
            right--;
        high = right;
        res[0] = low;
        res[1] = high;
        return res;
    }

35.Search Insert Position
思路:排好序的数组进行查找,很明显用二分法。如果数组为空,返回0,然后判断是不是小于第一个数和最后一个数。每次取数组中间那个数进行比较,如果相等,则返回下标,小于target,则left = mid + 1,大于target,则right= mid,为什么不是right = mid - 1,其实这里是mid或者mid - 1都可以,如果是mid的话,后面没找到target,则返回right,如果是mid - 1的话,最后返回的是left,而且while循环条件是left<=right。

 int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        if (nums.empty())
            return 0;
        if (nums[0] >= target)
            return 0;
        if (nums[n-1] < target)
            return n;
        int left = 0,right = n - 1;
        int mid;
        while (left < right) {
            mid = (left + right) / 2;
            if (nums[mid] == target)
                return mid;
            else if (nums[mid] < target) 
                left = mid + 1;
            else 
                right = mid;
        }
        return right;
    }

36.Valid Sudoku
思路:需要访问每一个元素,所以复杂度最低也就是O(n^2)新建3个bool型的二维数组,然后遍历每一个元素,判断一行,一列和一个box是否有重复元素。判断思路是,如果vector[0] = 5,那么就让vector[vector[0]],也就是vector[5] = true。然后就是box怎么确定下标位置,3 * (i / 3) + j / 3][c]。

bool isValidSudoku(vector<vector<char>>& board) {
        int m = board.size();
        int n = board[0].size();
        vector<vector<bool>> row(m,vector<bool>(n,false));
        vector<vector<bool>> col(m,vector<bool>(n,false));
        vector<vector<bool>> box(m,vector<bool>(n,false));

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                char ch = board[i][j];
                if (ch >= '1' && ch <= '9') {
                    int c = ch - '1';
                    if (row[i][c] || col[c][j] || box[3 * (i / 3) + j / 3][c])
                        return false;
                    row[i][c] = true;
                    col[c][j] = true;
                    box[3 * (i / 3) + j / 3][c] = true;
                }
            }
        }
        return true;
    }

38.Count and Say
思路:首先明确的是必须从“1”开始。这道题的意思就是要把前一个数用数描述出来,比如前一个数“1211”,那么就是1个1,1个2,2个1,所以这个数就是“111221”。遍历字符串每个数字,判断有没有下一个数字,并且判断是不是和前一个数一样,如果一样,count+1,当不一样的时候,就说明可以添加到字符串中去,跳出while循环,temp += to_string(count) + res[i].

string countAndSay(int n) {
        if (n < 1)
            return "";
        string res = "1";
        while (--n) {
            string temp = "";
            for (int i = 0; i < res.size(); i++) {
                int count = 1;
                while (i+1 < res.size() && res[i+1] == res[i]) {
                    count++;
                    i = i + 1;
                }
                temp += to_string(count) + res[i];
            }
            res = temp;
        }
        return res;
    }

39

40Combination Sum II
思路:和39一样,都是用DFS,但是要有判断是否重复。

vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> res;
        vector<int> out;
        dfs(candidates,target,out,res,0);
        return res;
    }
    void dfs(vector<int>& candidates,int target,vector<int>& out,vector<vector<int>>& res,int start) {
        if (target < 0) 
            return;
        else if (target == 0) {
            res.push_back(out);
        }
        else {
            for (int i = start; i < candidates.size(); i++) {
                if (i > start && candidates[i] == candidates[i - 1]) continue;
                out.push_back(candidates[i]);
                dfs(candidates,target - candidates[i],out,res,i+1);
                out.pop_back();
            }
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值