LeetCode 1 ~ 5 题解

LeetCode - 1 双指针+读写优化

Two Sum

耗时

runtime 4 ms, beats 99.95% of cpp submissions.

题意

给定一个有序数组 nums 和一个目标值 target ,在数组 nums 中找出两个不同位置的数 a 和b,使得 a + b == target,返回a 和 b 在数组 nums 中的下标。

题解

首先用pair 将数组中的值和下标组合在一起,放在 vector 中,对vector进行排序。然后开两个指针,分别指向数组头部和尾部。相加两个指针所指元素并和 target 进行比较,如果大于 target,说明两数之和过大,将尾部指针前移,反之将首部指针后移。

特别要说明的是,使用下面这段代码,可以大大提升 cin,cout 的读写速度。

static auto z = [](){
	    std::ios::sync_with_stdio(false);
	    std::cin.tie(0);
	    return 0;
	}();	

std::ios::sync_with_stdio(false);是关闭C 和 C++标准IO流的同步。也就是说默认情况下,允许 C 和 C++标准IO流的混用,共用缓冲区。关闭后就使用各自缓冲区,可以加快程序速度,但是此时混用两种风格输入输出是很危险的。
默认情况下,cin 和 cout 是绑定,在 cin 获取用户输入内容时,会先刷新 cout 缓冲区将内容输出,再阻塞程序获取输入。而std::cin.tie(0); 则是解除 cin 和 cout 的绑定,能加快程序执行,但副作用是会导致 cin 先于 cout 执行,比如程序可以已经开始阻塞来接收用户输入,但是“请输入”提示符还没打印出来。
由于此时我们此时的代码主要用于解题,而不是实际生产,所以一般情况下使用这两个语句没有问题,还能够加快程序运行速度。

代码

static auto z = [](){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    return 0;
}();
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<pair<int,int>>v;
        int len = nums.size();
        for(int i=0;i<len;++i){
            v.push_back(pair<int,int>(nums[i],i));
        }
        sort(v.begin(),v.end());
        int i = 0,j = len - 1;
        vector<int>ans;
        while(i < j){
            if(v[i].first + v[j].first == target){
                ans.push_back(v[i].second);
                ans.push_back(v[j].second);
                break;
            }
            else if(v[i].first + v[j].first < target){
                i++;
            }
            else{
                j--;
            }
        }
        
        return ans;
    }
};

LeetCode - 2 链表模拟加法

Add Two Numbers

耗时

runtime 16 ms, beats 100% of cpp submissions.

题意

给两个非空链表,链表每个节点代表一个数字,每个链表倒叙表示一个十进制的数,将两链表按十进制进行相加后返回一个新的链表。

题解

模拟加法算式运算。

需要注意的地方主要是两个点:

  1. 两个链表长度不一致。
  2. 进位,尤其是链表末尾的进位,需要新建节点。

最后就是操作上的一些小 trick,用得好的话,可以节省不少运行时间,具体的可以直接看代码。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
static const auto io_sync_off = []()
{
    // turn off sync
    std::ios::sync_with_stdio(false);
    // untie in/out streams
    std::cin.tie(nullptr);
    return nullptr;
}();

class Solution {
public:
	ListNode* addTwoNumbers(ListNode* l1, ListNode* l2){
		ListNode* tmp = new ListNode(0);
		int carrybit = 0;
		ListNode* ans = tmp;
		while(l1 && l2){
			tmp = tmp -> next = new ListNode(0);	
			tmp -> val = l1 -> val + l2 -> val + carrybit;
			carrybit = (tmp -> val) / 10;
			tmp -> val %= 10;
			l1 = l1 -> next;
			l2 = l2 -> next;
		}
		if(l1){
			tmp -> next = l1;	
		}
		else{
			tmp -> next = l2;
		}
		while(carrybit){
			if(tmp -> next == NULL){
				tmp -> next = new ListNode(0);
			}
			tmp = tmp -> next;
			tmp -> val ++;
			carrybit = (tmp -> val) / 10;
			tmp -> val %= 10;
		}
		return ans -> next;
	}
};

LeetCode - 3 滑动窗口

Longest Substring Without Repeating Characters

耗时

runtime 20ms, beats 79.98% of cpp submissions.

题意

给一个字符串,求一个最长子串的长度,该子串需要满足其中所有元素都不相同。

题解

遍历字符串,开一个hash_map记录元素在当前位置之前,在字符串中出现的最后位置。
开一个指针 pre 记录使[pre,i]子串满足条件的 pre 的最小位置。

代码

class Solution {
public:
	int lengthOfLongestSubstring(string s){
		unordered_map<char,int>hash_map;
		int mx = 0;
		int pre = -1;
		size_t len = s.size();
		for(int i=0;i<len;++i){
			if(hash_map.find(s[i]) != hash_map.end() && pre < hash_map[s[i]]){
                pre = hash_map[s[i]];
			}
			else{
				mx = max(mx,i - pre);
			}	
			hash_map[s[i]] = i;
		}

		return mx;
	}
};

LeetCode - 4 二分查找

Median of Two Sorted Arrays

耗时

runtime 20ms, beats 98.46% of cpp submissions.

题意

给定两个已排序的数组,其长度分别为 m 和n,找出两个数组中的中间数,时间复杂度为 log(m+n)。

题解

首先时间复杂度是 log(m+n),就很容易想到构造一个能在两个数组之间进行二分查找的函数。
然后需要分两种情况:

  1. m+n 为偶数,这种中间数就是两个数组中的两个元素的平均值。这两个元素的位置又有四种组合,分别求出来进行判断,找出最终解。
  2. m+n 为奇数,这种中间数就是两个数组的某一个元素。这个元素的位置只有两种情况,分别求出判断,得出答案。

这题的难点就在于构造跨两个数组的二分查找了,细节需要考虑仔细才能一次 AC。

我的这个解法虽然速度上还可以,但是写法过于繁杂。leetcode 官方题解有一些非常简洁的写法,很值得学习。姿势水平还不够高,继续努力。

官方题解链接

代码

static auto z = [](){
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    return 0;
}();
class Solution {
public:
	int solve(vector<int>& num, int len, int val, int need_l, int need_r){
		int res = 0;
       if(need_l < 0){
            res = 1;
        }
        else if(need_r < 0){
            res = -1;
        }
		else if(need_l > 0 && num[need_l-1] > val){
			res = -1;//too small
		}
		else if(need_l < len && num[need_l] < val){
			res = 1;//too big
		}
		else if(need_r > 0 && num[len - need_r] < val){
			res = 1;
		}
		else if(need_r < len && num[len - 1 - need_r] > val){
			res = -1;
		}
		
		return res;	
	}
	int binarySearch(vector<int>& nums1, int len1, vector<int>& nums2, int len2, int total_l, int total_r){
		int l = 0, r = len1, res = len1;
		while(l < r){
            // cout << l << ' ' << r << endl;
			int mid = (l + r) >> 1;
			int tmp = solve(nums2, len2, nums1[mid], total_l - mid, total_r - (len1 - 1 - mid) );
			if(tmp == 0){
				res = mid;
                break;
			}	
			else if(tmp == 1){
				r = mid;
			}
			else{
				l = mid + 1;
			}
		}	
		
		return res;
	}
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
		int len1 = nums1.size();
		int len2 = nums2.size();		
		int total = (len1 + len2 - 1) >> 1;
		if((len1 + len2) % 2 == 0){
			int a1 = binarySearch(nums1, len1, nums2, len2, total, total+1);
            // cout << a1 << endl;
			int a2 = binarySearch(nums1, len1, nums2, len2, total+1, total);
            // cout << a2 << endl;
			int b1 = binarySearch(nums2, len2, nums1, len1, total, total+1);
            // cout << b1 << endl;
			int b2 = binarySearch(nums2, len2, nums1, len1, total+1, total);
            // cout << b2 << endl;
			if(a1 < len1 && a2 < len1){
				return (nums1[a1] + nums1[a2]) / 2.0;
			}
			else if(a1 < len1 && b2 < len2){
				return (nums1[a1] + nums2[b2]) / 2.0;	
			}
			else if(b1 < len2 && b2 < len2){
				return (nums2[b1] + nums2[b2]) / 2.0;
			}
			else if(a2 < len1 && b1 < len2){
				return (nums1[a2] + nums2[b1]) / 2.0;
			}
		}
		else{
			int a = binarySearch(nums1,len1,nums2,len2,total,total);
            // cout << a << endl;
			if(a < len1){
				return nums1[a];
			}
			int b = binarySearch(nums2,len2,nums1,len1,total,total);
			// cout << b << endl;
			if(b < len2){
				return nums2[b];
			}
		}
        
        return 0;
    }
};

LeetCode - 5 Manachar

Longest Palindromic Substring

耗时

runtime 4ms, beats %99.73 of cpp submissions.

题意

求字符串中的最长回文子串。

题解

可以参考我之前的文章,上面有对求最长回文串的详细讲解。
《求最长回文串的几种做法》

代码

static auto x = [](){
    // turn off sync
    std::ios::sync_with_stdio(false);
    // untie in/out streams
    std::cin.tie(NULL);
    return 0;
}();
class Solution {
public:
   
    string longestPalindrome(string s) { 
        if(s.length()==0) return "";
        string strTemp{"$#"};
      
        for(int i=0;i<s.length();++i){
            strTemp+=s[i];
            strTemp+='#';
        }
        vector<int> nTemp(strTemp.size(),1);
        int TempMaxIndex=0,TempMaxMid=0,ansCount=0,ansIndex=0;
        for(int i=0;i<strTemp.size();++i){
            if(i<TempMaxIndex) 
                nTemp[i]=min(nTemp[2*TempMaxMid-i],TempMaxIndex-i);
            
            while(strTemp[i-nTemp[i]]==strTemp[i+nTemp[i]])
                nTemp[i]++;
            if(nTemp[i]+i>TempMaxIndex)
            {
                TempMaxIndex=nTemp[i]+i;
                TempMaxMid=i;
            }
            if(nTemp[i]>ansCount){
                ansCount=nTemp[i];
                ansIndex=i;
            }
        }
                      
        return s.substr((ansIndex-ansCount)/2,ansCount-1);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值