leetcode解題思路分析(二十二)148 - 154題

  1. 排序鏈表
    在 O(n log n) 時間複雜度和常數級空間複雜度下,對鏈表進行排序。

歸併排序三部曲:
fast-slow找中點:直到快的走到了末尾,然後慢的所在位置就是中間位置,這樣就分成了兩段
將鏈表分成兩部分
合併兩個有序鏈表

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        return mergesort(head);
    }
    ListNode* mergesort(ListNode* node)
    {
        if(!node || !node->next) return node;
        ListNode *fast=node;//快指針走兩步
        ListNode *slow=node;//慢指針走一步
        ListNode *brek=node;//斷點
        while(fast && fast->next)
        {
            fast=fast->next->next;
            brek=slow;
            slow=slow->next;
        }
        brek->next=nullptr;
        ListNode *l1=mergesort(node);
        ListNode *l2=mergesort(slow);
        return merge(l1,l2);
    }
    ListNode* merge(ListNode* l1,ListNode* l2)
    {
        if(l1==NULL)
        {
            return l2;
        }
        if(l2==NULL)
        {
            return l1;
        }
        if(l1->val < l2->val)
        {
            l1->next=merge(l1->next,l2);
            return l1;
        }
        else
        {
            l2->next=merge(l2->next,l1);
            return l2;
        }
    }
};

  1. 直線上最多的點數
    給定一個二維平面,平面上有 n 個點,求最多有多少個點在同一條直線上。

分類討論:
1.使用一個變量dup記錄重複的點;
2.使用Map,構造一個pair<double,int>來記錄:前者爲斜率值,後者爲計數(注意討論斜率不存在的情況否則會造成除法異常)
但本題難在高精度斜率的計算,樣例中有一個數據會使你的long double的精度都失效。所以這時候如果仍然採用傳統的斜率判別法則需要運用高精度除法算法。
所以,基於此需要對Map的元素進行改變,構造pair<string,int>此時使用字符串來保存斜率(代碼中精度我取了小數點後20位)

class Solution {
public:
   string Slope(int a, int b) {
	string s = "";
	char c;
	int p;
	stringstream ss;  //使用字符流將整數部分直接轉換成字符串。
	p = a / b;
	ss << p;
	ss >> s;
	s += '.';
	for (int i = 0; i < 20; i++)  //小數點後模擬除法過程,此時精度爲20位。
	{
		a = a % b * 10;
		c = (char)(a / b + 48);
		s += c;
	}
	return s;
}
int maxPoints(vector<vector<int>>& points) {
	map<string, int>Dic;   //構造映射表,string類型存儲斜率,int類型存儲相應的點數。
	int i, j, x1, x2, y1, y2, ans, res = 2, temp, dup;
	string k;
	if (points.size() <= 2)
		return points.size();
	for (i = 0; i < points.size(); i++) {
		dup = 0;
		ans = 0;
		for (j = i + 1; j < points.size(); j++) {
			x1 = points[i][0];
			x2 = points[j][0];
			y1 = points[i][1];
			y2 = points[j][1];
			if (x1 == x2 && y1 == y2)   //情況一:重複的點。
				dup++;
			else if (x1 == x2 && y1 != y2) {  //情況二:斜率不存在的點。
				if (Dic.find(" ") == Dic.end())
					Dic.insert(pair<string, int>(" ", 2));
				else
					Dic[" "]++;
				ans = max(Dic[" "], ans);
			}
			else {   //情況三:斜率存在的點。
				k = Slope(y1 - y2, x1 - x2);
				if (Dic.find(k) == Dic.end())
					Dic.insert(pair<string, int>(k, 2));
				else
					Dic[k]++;
				ans = max(Dic[k], ans);
			}
		}
		if (ans == 0)   //注意,若遍歷完只有重複的點,則需要加一,因爲dup是從0開始計數的。
			res = max(res, dup + 1);
		else
			res = max(res, ans + dup);
		Dic.clear();
		k = "";
	}
	return res;
}
};

  1. 逆波蘭表達式求值
    根據逆波蘭表示法,求表達式的值。

很無聊的一道題,知道什麼事波蘭表達式,用一個堆棧就可以了

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        if(tokens.empty()) return 0;
        stack<int> numst;
        stringstream ss;
        

        for(int i = 0;i<tokens.size();++i)
        {
            string c = tokens[i] ;
            if(c == "+"||c == "-"||c == "*"||c == "/" ) 
            {
                int temp1 = numst.top(); numst.pop();
                int temp2 = numst.top(); numst.pop();
                int temp3 = 0;
                if(c == "+") {temp3 = temp1+temp2; numst.push(temp3);}
                else if(c == "-") {temp3 = temp2-temp1; numst.push(temp3);}
                else if(c == "*") {temp3 = temp1*temp2; numst.push(temp3);}
                else{temp3 = temp2/temp1; numst.push(temp3);}
            }
            else
            {
            int number;
            ss.clear();
            ss<<c;
            ss>>number;
            
            numst.push(number);
            }
        }
        return numst.top();

        

    }
};

  1. 翻轉字符串裏的單詞
    給定一個字符串,逐個翻轉字符串中的每個單詞。

如果追求時間,則比較好的方法是額外建一個棧存儲,之後依次讀出即可。如果追求空間,則原地轉換更佳,方法是先將整個字符串反轉,然後判斷每個單詞再局部反轉


class Solution {
public:
    string reverseWords(string s) {
        reverse(s.begin(), s.end());
        int size = (int)s.size();
        int start = 0; //單詞開始
        int end = 0;   //單詞末尾
        int index = 0; 
        for (; start < size; start++) {
            if (s[start] == ' ') continue;
            if (index != 0){
                //第二個單詞開始 開頭需要插一個空格
                s[index++] = ' ';
            }
            end = start;
            //替換原來的s 一直到空格爲止
            while (end < size && s[end] != ' ') {
                s[index++] = s[end++];
            }
            //index指向了單詞末尾的 下一個字符
            //一個單詞的長度
            int len = end - start;
            //index - len就是單詞開始的地方
            //s.begin() + index - len 單詞開始的位置
            //s.begin() + index 單詞結束的位置
            reverse(s.begin() + index - len, s.begin() + index);
            //更新下一個單詞的開始位置 start正好指向了空格的位置
            start = end;
            //這一輪循環結束 之後 start++
            //如果只有一個空格 start正好 指向了下一個單詞的開始位置
            //如果有多個空格,則指向了下一個空格 下次循環開頭會跳過
        }
        //去除末尾的空格和沒有用的字符
        s.erase(s.begin() + index, s.end());
        return s;
    }
};
  1. 乘積最大子數組
    給你一個整數數組 nums ,請你找出數組中乘積最大的連續子數組(該子數組中至少包含一個數字)。

本題重點在於需要維護一個Min和一個max,因爲負數的乘法很可能使得最大最小瞬間顛倒,採取動態規劃思想遍歷一遍即可


class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int n = nums.size();
        if(n == 0){
            return 0;
        } else if(n == 1) {
            return nums[0];
        }
        int p = nums[0];
        int maxP = nums[0];
        int minP = nums[0];
        for(int i = 1; i < n; i++) {
            int t = maxP;
            maxP = max(max(maxP * nums[i], nums[i]), minP *nums[i]);
            minP = min(min(t * nums[i], nums[i]), minP * nums[i]);
            p = max(maxP, p);
        }
        return p;
    }
};


  1. 尋找旋轉排序數組中的最小值

二分查找

class Solution {
public:
    int findMin(vector<int>& nums) 
    {
        int left = 0;
        int right = nums.size() - 1;
        while (left < right) 
        {
            int mid = left + (right - left) / 2;
            if (nums[mid] > nums[right]) 
            {          
                left = mid + 1;
            } 
            else 
            {                               
                right = mid;
            }
        }
        return nums[left];
    }
};


  1. 尋找旋轉排序數組中的最小值2
class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0, right = nums.size() - 1;

        while(left < right){
            if(nums[left] < nums[right])
                return nums[left];
            int mid = (left + right) / 2;
            if(nums[mid] == nums[left] && nums[mid] == nums[right])
                right--;
            else if(nums[left] <= nums[mid])    //[left, mid]連續
                left = mid + 1;
            else                            //[mid, right]連續
                right = mid;    
        }
        return nums[left];
    }
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章