LeetCode刷题记录 1-5

马上要面试了,把前些天在LeetCode上刷的题再看一遍。

写上注释,算复习了,也方便以后复习。

带 * 号的为忘记怎么做的。

1. 5. 最长回文子串(动态规划)

class Solution {
public:
    string longestPalindrome(string s) {
        int len = s.length();
        int dp[1005][1005];
        // 记录最长回文串的开始位置及长度
        int index = 0, max = 1;
        for (int i = 0; i < len; i++) {
            for (int j = i; j < len; j++) {
                // 初始认为[i,j]不是回文串
                dp[i][j] = 0;
                // 单个字符一定是回文串
                if (i == j) dp[i][j] = 1;
                // 两个字符组成的串是不是回文串取决于这两个字符是否相等
                if (j == i + 1) {
                    dp[i][j] = (s[i] == s[j]);
                    // 这里一定要更新,否则会出错
                    if (dp[i][j]) {
                        index = i;
                        max = 2;
                    }
                }
            }
        }
        // 最外层循环为长度才可满足最优子结构
        for (int l = 3; l <= len; l++) {
            for (int i = 0; i < len - l + 1; i++) {
                int j = i + l - 1;
                // i为串的起点,j为串的终点
                dp[i][j] = (dp[i+1][j-1] && (s[i] == s[j]));
                if (dp[i][j]) {
                    max = l;
                    index = i;
                }
            }
        }
        // 注意用法
        return s.substr(index, max);
    }
};

2. 11. 盛最多水的容器(对撞指针)

class Solution {
public:
    int maxArea(vector<int>& height) {
        int max = -1;
        int n = height.size();
        int start = 0, end = n - 1;
        // start和end分别指向左右两个板子,因为必须有两个板子,所以结束条件为start < end
        while (start < end) {
            int temp;
            // 将高的向中间移,不可能让面积增大,所以下面两种情况分别是让end--和start++
            if (height[start] > height[end]) {
                temp = height[end] * (end - start);
                end --;
            }
            else {
                temp = height[start] * (end - start);
                start ++;
            }
            if (max < temp) max = temp;
        }
        return max;
    }
};

3*. 31. 下一个排列(脑门题)

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int n = nums.size();
        int flag = 1;
        int i;
        // 从后向前,找到第一对相邻的两个数,满足后面的数大于前面的数
        // 因为对于一个本身递增的序列没有办法再找到比它更大的了
        for (i = n - 1; i > 0; i--) {
            if (nums[i] > nums[i-1]) {
                flag = 0;
                break;
            }
        }
        // 如果没找到,什么也不做
        if (flag) {
        }
        // 如果找到了,i指向两数中靠后的,例如右方例子中,i指向6: 1 2 6 5 4 2 2 2 1 1
        else {
            // [i...n-1](自右向左是递增的)中找到第一个比i-1位置处值大的,交换
            // 这样才有可能变得更大,变化后为 -> 1 4 6 5 2 2 2 2 1 1
            for (int j = n - 1; j >= i; j--) {
                if (nums[j] > nums[i-1]) {
                    swap(nums[j], nums[i-1]);
                    break;
                }
            }
        }
        // 对[i...n-1]范围做个镜像 -> 1 4 1 1 2 2 2 2 5 6
        // 这个循环如果没找到后数大于前数的,i为0,也满足
        for (int j = 0; j < (n - i) / 2; j++) {
            swap(nums[j+i], nums[n-j-1]);
        }
    }
};

4. 3. 无重复字符的最长子串(哈希表+滑动窗口)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 因为键有限,所以用一个数组模拟哈希表,存的是最后一次出现的位置
        int hash[256];
        for (int i = 0; i < 256; i++) hash[i] = -1;
        int n = s.length();
        // 滑动窗口的边界
        int left = 0, right = 0;
        int m = -1;
        // 窗口每次无论如何都向右扩展,不行再缩小左边界
        while (right < n) {
            // 当前窗口中没有当前纳入的字符的情况,尝试更新最值
            if (hash[s[right]] == -1 || hash[s[right]] < left) {  
                m = max(m, right - left + 1);
            }
            // 当前窗口中有当前纳入字符,缩小左边界
            else {
                left = hash[s[right]] + 1;
                // 这种情况不用更新最值,因为不可能有最值产生,因为右侧扩展1,左侧至少缩小1
            }
            // 更新字符位置
            hash[s[right]] = right;
            right ++;
        }
        return m == -1 ? 0 : m;
    }
};

5. 75. 颜色分类(对撞指针)

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int n = nums.size();
        int left = 0;
        int right = n - 1;
        // 遍历一遍数组
        for (int i = 0; i <= right; i++) {
            // 为0则换到左边,left处的值一定是1,不用i--
            if (nums[i] == 0) {
                swap(nums[left], nums[i]);
                left ++;
            }
            // 为2则换到右边,下次还要再检测i处的值,所以再i--
            else if (nums[i] == 2){
                swap(nums[right], nums[i]);
                right --;
                i --;
            }
        }
    }
};
发布了110 篇原创文章 · 获赞 26 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/liujh_990807/article/details/104075554