2019年7月

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

问题描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。

示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array

思路

emmmm,复杂度为O(n)

题解

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int n=nums.size();
        vector<int> ret;
        int min=-1;
        int max=-1;
        for(int i=0;i<n;i++){
            if(target==nums[i]){
                min=i;
                break;
            }
        }
        for(int i=0;i<n;i++){
            if(target==nums[i]){
                max=i;
            }
        }
        ret.push_back(min);
        ret.push_back(max);
        return ret;
    }
};

全排列

问题描述

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutations

思路

回溯算法,和以前的做法一样,详情见以前的题目。

题解

class Solution {
public:
    bool visited[100] = {false};
    vector<int> B;
    vector<vector<int> > A;

    vector<vector<int>> permute(vector<int> &nums) {
        dfs(nums,A,0);
        return A;
    }
    void dfs(vector<int> &nums, vector<vector<int>> &A, int step) {
        int n = nums.size();
        if (step == n) {
            A.push_back(B);
            return;
        }
        for (int i = 0; i <n;i++)
        {
            if(visited[i]==false)
            {
                visited[i]=true;
                B.push_back(nums[i]);
                dfs(nums,A,step+1);
                visited[i]= false;
                B.pop_back();
            }
        }
    }
};

搜索旋转排序数组

问题描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。

示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4

示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array

思路

题目中要求算法时间复杂度必须是 O(log n) 级别->用二分查找。
题目中给出数组在某个点进行了旋转,数组在旋转之前是升序排列的,因此,最小的点即为旋转点。
找到了旋转点之后,将数组至多分为两个二分查找。
在两部分分别进行二分查找后,没找到目标值返回-1,如果找到返回坐标i,i一定大于-1.因此在两部分二分查找的结果中找最大值即可。

题解

class Solution {
public:
    int search(vector<int> &nums, int target) {
        int n = nums.size();
        if(n==0){
            return -1;
        }
        int min = nums[0];
        int flag = 0;
        for (int i = 1; i < n; i++) {
            if (min > nums[i]) {
                min = nums[i];
                flag = i;
            }
        }

        int location1 = refen(-1, nums, 0, flag - 1, target);
        int location2 = refen(-1, nums, flag, n - 1, target);
        return max(location1,location2);
    }

    int refen(int location, vector<int> &nums, int first, int last, int target) {
        int mid;
        while (first <= last && first >= 0 && last <= nums.size()) {
            mid = (first + last) / 2;
            if (target > nums[mid]) {
                first = mid + 1;
            } else if (target < nums[mid]) {
                last = mid - 1;
            } else {
                location = mid;
                break;
            }
        }
        return location;
    }
};

盛最多水的容器

问题描述

给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器,且 n 的值至少为 2。
question_11 (1).jpg
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/container-with-most-water

思路

容器容纳水的多少,取决于两个方面--两个直线间的距离以及两个直线中比较短的那个高度
本题的思想是双指针:
first=0;last=n-1;因为取决于比较短的那个高度,所以,每次短的那个指针向高的方向移动,来寻求高度的最大值。在这个过程中,直线之间的长度会变小,所以,这就需要在这个高度不断增大,长度不断较小的过程中寻求一个最大的值。

题解

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n=height.size();
        int first=0;
        int last=n-1;
        int smax=0;
      
        while (first<last){
            int sa=min(height[first],height[last])*(last-first);
            if(s>smax){
                smax=s;
            }
            if(height[first]<height[last]){
                first++;
            }
            else if(height[first]>height[last])
            {
                last--;
            } else{
                first++;
            }
        }
        return smax;
    }
};

电话号码的字母组合

问题描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

17_telephone_keypad.png

示例:
输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number

思路

首先在电话号码的数字和字母之间进行一个映射, map<char, string> table;
vector ret作为最后返回的结果,cur作为中间暂存结果,当递归次数index等于digits.length()时,将cur存入到ret中
当index小于digits.length()时,

for(int i=0;i<table[digits[index]].length();i++){
            dfs(digits,cur + table[digits[index]][i],index + 1);
        }

题解

class Solution {
public:
    map<char, string> table;

    void init() {
        table['2'] = "abc";
        table['3'] = "def";
        table['4'] = "ghi";
        table['5'] = "jkl";
        table['6'] = "mno";
        table['7'] = "pqrs";
        table['8'] = "tuv";
        table['9'] = "wxyz";
    }

    int len;
    vector<string> ret;

    vector<string> letterCombinations(const string &digits) {
        init();
        len = digits.length();
        if(len==0) return ret;
        dfs(digits, "",0);
        return ret;
    }

    void dfs(string digits, const string &cur,int index) {
        if (index == len) {
            ret.push_back(cur);
            return;
        }
        for(int i=0;i<table[digits[index]].length();i++){
            dfs(digits,cur + table[digits[index]][i],index + 1);
        }

    }
};