双指针问题总结

167.两数之和
题解:因为数组已按照非降序排列,所以可采用头尾双指针遍历(i为头,j为尾)。如果numbers[i] + numbers[j] > target,则大于i的其他数与numbers[j]相加都大于target,此时令j减小继续进行判断;当numbers[i] + numbers[j] < target时,比j小的其他数与numbers[i]相加均小于target,所以使i加一继续判断。代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        vector<int> a;
        int i = 0, j = numbers.size() - 1;
        while(i < j)
        {
            if(numbers[i] + numbers[j] == target)
                break;
            else if(numbers[i] + numbers[j] < target)
                i++;
            else 
                j--;
        }
        a.push_back(i + 1);
        a.push_back(j + 1);
        return a;
    }
};

633.平方数之和
题解:与上题类似,本题只需寻找[0, sqrt( c )] 之间中是否存在两个数满足条件。需要注意的是由于c的范围为(0,2^31 - 1), 因此在寻找满足条件的值中会出现超出int范围的情况,因此采用long类型数据;与上一题的区别是存在相同的数相加的情况,因此循环条件有所不同。

class Solution {
public:
    bool judgeSquareSum(int c) {
        long i = 0, j = (int)sqrt(c);
        while(i <= j)
        {
            if(i * i + j * j == c)
                return true;
            else if(i * i + j*j < c)
                i++;
            else 
                j--;
        }
        return false;
    }
};

680.验证回文字符串
题解:最多删除一个字符即在前后字符出现不同时删除其中一个判断剩下的子串是否为回文。代码如下:

class Solution {
public:

    bool validPalindrome(string s) {
        int i = 0, j = s.size() - 1;
        while(i < j)
        {
            if(s[i] == s[j])
            {
                i++;
                j--;
            }
            else
                return isPalindrome(s, i+1, j) || isPalindrome(s, i, j-1);
        }
        return true;
    }
    bool isPalindrome(string& s, int i, int j)
    {
        while(i < j)
        {
            if(s[i] == s[j])
            {
                i++;
                j--;
            }
            else   
                return false;
        }
        return true;
    }
};

88.合并两个有序数组
题解:为两个数组各自设定一个指针,比较两个数组之间数的大小从而实现升序合并。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        vector<int> temp;
        int i = 0, j = 0;
        while(i < m && j < n)
        {
            if(nums1[i] < nums2[j])
            {
                temp.push_back(nums1[i]);
                i++;
            }
            else
            {
                temp.push_back(nums2[j]);
                j++;
            }
        }
        if(i == m)	//i = m 表示nums1数组合并完毕剩下nums2数组中的数
        {
            while(j < n)
            {
                temp.push_back(nums2[j]);
                j++;
            }
        }
        if(j == n)	// i = n表示nums2数组合并完毕剩下nums1数组中的数
        {
            while(i < m)
            {
                temp.push_back(nums1[i]);
                i++;
            }
        }
        nums1.assign(temp.begin(), temp. end());
    }
};

524.通过删除字母匹配到字典里最长单词
题解:确立两个指针,一个指向s字符串,一个指向dictionary[j],逐个遍历比较是否为s的子串,并比较是否为最长子串,记录子串的地址。代码如下:

class Solution {
public:
    string findLongestWord(string s, vector<string>& dictionary) {
        int max = 0, index = -1;
        for(int i = 0;i<dictionary.size();i++)
        {
            int x = 0, j = 0;
            while(x < s.size() && j < dictionary[i].size())
            {
                if(s[x] == dictionary[i][j])
                {
                    x++;
                    j++;
                }
                else
                    x++;
            }
            if(j == dictionary[i].size())
            {
                if(j > max)
                {
                    max = j;
                    index = i;
                }
                else if(j == max)
                {
                    if(dictionary[index] > dictionary[i])
                    {
                        index = i;
                    }
                }
            }
        }
        if(index == -1)
            return "";
        else
            return dictionary[index];
    }
};

142.环形链表||
题解:通过快慢指针寻找。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL)
            return NULL;
        ListNode *slow = head, *quiet = head;
        while(1)
        {
            if(quiet->next == NULL || quiet->next->next == NULL)
                return NULL;
            slow = slow->next;
            quiet = quiet->next->next;
            if(slow == quiet)		//第一次相遇
            {
                quiet = head;
                break;
            }
        }
        while(quiet != slow)	//从头开始第二次相遇
        {
            quiet = quiet->next;
            slow = slow->next;
        }
        return quiet;
    }
};

76.最小覆盖子串
题解:采用滑动窗口的方法处理,即定义first与end指针在s字符串中滑动,使得滑动窗口中的字符包含t中字符,此时记录字符串及长度,并将first指针加一,看滑动窗口中是否缺失字符,若缺失则移动end指针补,若不缺则继续令first指针加一,从而找到最小包含t的子串。在判断滑动窗口中是否包含t中字符时,可以使用map存储t中字符出现的次数,通过遍历s,判断其是否大于0来确定是否为t中字符,并定义sum来统计s中找到与t中匹配的字符个数。同时将大于0的map值定义为需要找到的字符,小于0的定义为多余的字符。

class Solution {
public:
    string minWindow(string s, string t) {
        map<char, int> a;
        for(int i = 0;i<t.size();i++)
        {
            a[t[i]]++;
        }
        int first = 0, end = 0, min = 100001;
        int sum = 0;
        string res = "";
        while(first < s.size())
        {
            while(sum != t.size() && end < s.size())
            {
                if(a[s[end]] > 0)
                    sum++;
                a[s[end]]--;	
                end++;
            }
            if(sum != t.size() && end == s.size())	//遍历完毕无符合情况
            {
                break;
            }
            if(sum == t.size())
            {
                if(end - first < min)
                {
                    min = end - first;
                    res = s.substr(first, min);
                }
            }
            if(a[s[first]] == 0)
            {
                sum--;
            }
            a[s[first]]++;
            first++;
        }
        if(min == 100001)
        {
            return "";
        }
        else
            return res;
    }
};

340.至多包含k个不同字符的最长子串
题解:通过将end指针遍历s字符串找到k个字符所组成的字符串,然后与上题类似将first指针加一,再比较所找字符串的长度。

class Solution {
public:
    int lengthOfLongestSubstringKDistinct(string s, int k) {
		int end = 0, first = 0, max = 0;
		map<char, int> a;
		while (end < s.size())
		{
			a[s[end]] = end;
			while (a.size() > k)
			{	
				if(a[s[first]] == first)
					a.erase(s[first]);
				first++;
			}
			if(end - first + 1 > max)
			{
				max = end - first + 1;
			}
			end++;
		}
		return max;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: "双指针" 是一种算法思想,常用于数组或链表的操作中。在 Java 中,双指针的实现方法为使用两个指针变量同时遍历数组或链表。 下面是一个简单的双指针的代码实现例子: ``` int[] nums = {1, 2, 3, 4, 5}; int left = 0; int right = nums.length - 1; while (left < right) { int sum = nums[left] + nums[right]; if (sum == target) { // 双指针找到答案 return true; } else if (sum < target) { left++; } else { right--; } } return false; ``` 在这个例子中,`left` 指针指向数组的头部,`right` 指针指向数组的尾部。当两个指针指向的数字的和小于目标值时,我们将 `left` 指针右移;当两个指针指向的数字的和大于目标值时,我们将 `right` 指针左移。 如果找到了答案,就返回 `true`,否则返回 `false`。 ### 回答2: Java中的双指针是一种常用的算法思想,常用于解决数组或链表相关的问题双指针可以通过控制指针的移动来实现特定的功能。 在Java中,一般可以使用两种方式来实现双指针。 第一种方式是使用两个指针分别指向数组或链表的不同位置,然后根据题目的要求移动指针。具体的实现步骤如下: 1. 定义两个指针指向数组或链表的起始位置,例如p1和p2。 2. 根据题目的要求,移动指针p1和p2,可以通过p1++、p2++或p1--、p2--来实现。 3. 在移动指针的过程中,可以通过判断指针的位置来获取需要的结果。 第二种方式是使用快慢指针,一般用于查找链表中的环或判断链表是否有交点等问题。具体的实现步骤如下: 1. 定义两个指针,分别为快指针和慢指针,初始时都指向链表的起始位置。 2. 快指针每次移动两个位置,慢指针每次移动一个位置。 3. 如果链表存在环,快指针最终会追上慢指针,即快指针和慢指针相遇。可以利用这个性质来判断链表是否有环。 4. 在快指针和慢指针相遇后,可以根据题目要求来处理结果。 总结起来,Java中的双指针可以通过两个指针分别指向数组或链表的不同位置,或者通过快慢指针的方式来实现。具体的实现方式要根据题目的要求来确定,常用于解决数组或链表相关的问题。 ### 回答3: Java的双指针是指在算法和数据结构中,使用两个指针来解决问题的一种技术。双指针可用于在数组、字符串或链表中快速定位和比较元素。 通常情况下,我们可以使用两个指针来解决以下几种常见问题: 1. 两数之和:可以使用快慢指针,其中一个指针从头开始,另一个指针从尾开始,根据两个指针指向的元素大小进行比较,逐渐收敛直到找到两数之和为目标值。 2. 反转数组或字符串:可使用双指针法,一个指针从头开始,另一个指针从尾开始,对应位置元素进行交换,逐渐移动指针直到交叉或相遇。 3. 链表中的环检测:使用快慢指针法,一个指针每次移动一个节点,另一个指针每次移动两个节点,如果存在环,则两个指针最终会相遇。 4. 删除有序数组中的重复元素:使用快慢指针法,一个指针遍历数组,另一个指针指向去重后的位置,当快指针遇到不重复的元素时,将该元素移动到慢指针的位置,并使慢指针后移一位。 5. 合并有序数组:可以使用两个指针分别指向两个数组的末尾,从后往前比较大小,将较大的元素放入合并后的位置,然后将指针向前移动,直到将两个数组合并完毕。 以上只是双指针技术的一些常见应用,具体问题的解决方案可能会稍有差异。通过理解问题的特性和分析,我们可以选择合适的双指针策略,并编写出相应的Java代码来解决问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值