java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846 |
---|
思路一:双指针
可以使用双指针,不断从两个方向匹配值。而两个数的平方和不能大于c。所以范围只需限制在[0, c \sqrt[]{c} c?]
class Solution {
//时间复杂度O(根号c),空间复杂度O(1)
public boolean judgeSquareSum(int c) {
//双指针,因为任何数表示成两个比自己小的数的平方和时
//都不可能大于自己的平方根,故,只需要从0到sqrt(c)即可
//例如c=25, 5*5就已经25了,不可能有到6的情况,因为6*6=35已经比c大了
long left = 0, right = (long)Math.sqrt(c);//long类型避免溢出
while(left<=right){//左右指针,指向同一个值时,结束查找,表示没找着
long sum = left*left + right*right;
if(sum==c) return true;//如果找到返回true
else if (sum>c) right--;//如果值太大,右边缩小
else left++;//值太小,左边扩大
}
return false;//没找着返回false;
}
}
思路二:费马平方和定理: 对于形如
p=4k+1
的素数 p,存在整数 x 和 y,使得 p = x 2 + y 2 p = x^2 + y^2 p=x2+y2 其中 x 和 y 是整数.
- 加粗样式
class Solution {
public boolean judgeSquareSum(int c) {
for (int base = 2; base * base <= c; base++) {
// 如果不是因子,枚举下一个
if (c % base != 0) {
continue;
}
// 计算 base 的幂
int exp = 0;
while (c % base == 0) {
c /= base;
exp++;
}
// 根据 Sum of two squares theorem 验证
if (base % 4 == 3 && exp % 2 != 0) {
return false;
}
}
// 例如 11 这样的用例,由于上面的 for 循环里 base * base <= c ,base == 11 的时候不会进入循环体
// 因此在退出循环以后需要再做一次判断
return c % 4 != 3;
}
}
刷题一定要坚持,总结套路,不单单要把题做出来,要举一反三,也要参考别人的思路,学习别人解题的优点,找出你觉得可以优化的点。
- 单链表解题思路:双指针、快慢指针、反转链表、预先指针
- 双指针:对于单链表而言,可以方便的让我们遍历结点,并做一些额外的事
- 快慢指针:常用于找链表中点,找循环链表的循环点,一般快指针每次移动两个结点,慢指针每次移动一个结点。
- 反转链表:通常有些题,将链表反转后会更好做,一般选用三指针迭代法,递归的空间复杂度有点高
- 预先指针:常用于找结点,比如找倒数第3个结点,那么定义两个指针,第一个指针先移动3个结点,然后两个指针一起遍历,当第一个指针遍历完成,第二个指针指向的结点就是要找的结点
- 数组解题思路:双指针、三指针,下标标记
- 双指针:多用于减少时间复杂度,快速遍历数组
- 三指针:多用于二分查找,分为中间指针,左和右指针
- 下标标记:常用于在数组范围内找东西,而不想使用额外的空间的情况,比如找数组长度为n,元素取值范围为[1,n]的数组中没有出现的数字,遍历每个元素,然后将对应下标位置的元素变为负数或者超出[1,n]范围的正数,最后没有发生变化的元素,就是缺少的值。