725. 分隔链表
2021.9.22 每日一题
题目描述
给定一个头结点为 root 的链表, 编写一个函数以将链表分隔为 k 个连续的部分。
每部分的长度应该尽可能的相等: 任意两部分的长度差距不能超过 1,也就是说可能有些部分为 null。
这k个部分应该按照在链表中出现的顺序进行输出,并且排在前面的部分的长度应该大于或等于后面的长度。
返回一个符合上述规则的链表的列表。
举例: 1->2->3->4, k = 5 // 5 结果 [ [1], [2], [3], [4], null ]
示例 1:
输入:
root = [1, 2, 3], k = 5
输出: [[1],[2],[3],[],[]]
解释:
输入输出各部分都应该是链表,而不是数组。
例如, 输入的结点 root 的 val= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。
第一个输出 output[0] 是 output[0].val = 1, output[0].next = null。
最后一个元素 output[4] 为 null, 它代表了最后一个部分为空链表。
示例 2:
输入:
root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
输出: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
解释:
输入被分成了几个连续的部分,并且每部分的长度相差不超过1.前面部分的长度大于等于后面部分的长度。
提示:
root 的长度范围: [0, 1000].
输入的每个节点的大小范围:[0, 999].
k 的取值范围: [1, 50].
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/split-linked-list-in-parts
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
不算简单的模拟
思路很简单,但是代码实现起来还是比较困难的
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode[] splitListToParts(ListNode head, int k) {
ListNode node = head;
int l = 0;
while(node != null){
l++;
node = node.next;
}
int t = l / k;
int remain = l % k;
node = head;
ListNode[] res = new ListNode[k];
int tt = t;
int idx = 0;
while(idx < k){
res[idx] = node;
while(tt-- > 0 && node != null){
node = node.next;
}
if(remain > 0){
node = node.next;
remain--;
}
tt = t;
idx++;
}
idx = 1;
node = head;
while(idx < k && node != null){
if(node.next == res[idx]){
node.next = null;
node = res[idx];
idx++;
}
else
node = node.next;
}
return res;
}
}
我是不知道怎么写成一次遍历才分开写的
学一下一次怎么写
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode[] splitListToParts(ListNode head, int k) {
int l = 0;
ListNode node = head;
while(node != null){
node = node.next;
l++;
}
int t = l / k;
int remain = l % k;
node = head;
ListNode[] res = new ListNode[k];
int idx = 0;
while(idx < k && node != null){
res[idx] = node;
//因为要到达的是下一个起始节点的前一个节点
int step = t + (remain-- > 0 ? 1 : 0);
while(step-- > 1){
node = node.next;
}
ListNode cur = node.next;
node.next = null;
node = cur;
idx++;
}
return res;
}
}
326. 3的幂
2021.9.23 每日一题
题目描述
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x
示例 1:
输入:n = 27
输出:true
示例 2:
输入:n = 0
输出:false
示例 3:
输入:n = 9
输出:true
示例 4:
输入:n = 45
输出:false
提示:
-2^31 <= n <= 2^31 - 1
进阶:
你能不使用循环或者递归来完成本题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-three
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
首先,最常规的思路,就是一直除以3,如果余数不为0,那么就不是3的次幂;如果最后剩下1了,那么就是
class Solution {
public boolean isPowerOfThree(int n) {
while(n != 0 && n % 3 == 0){
n /= 3;
}
return n == 1;
}
}
然后打表,
class Solution {
static Set<Integer> set = new HashSet<>();
static{
int i = 1;
set.add(i);
while(i <= Integer.MAX_VALUE / 3){
i *= 3;
set.add(i);
}
}
public boolean isPowerOfThree(int n) {
return n > 0 && set.contains(n);
}
}
然后注意,我刚开始写的是这样打表的,然后报的是内存溢出的错误,想了一下,肯定是i*3超出范围了
class Solution {
static Set<Integer> set = new HashSet<>();
static{
int i = 1;
set.add(i);
//错误代码
while(i * 3 <= Integer.MAX_VALUE){
i *= 3;
set.add(i);
}
}
public boolean isPowerOfThree(int n) {
return n > 0 && set.contains(n);
}
}
因为3是质数,所以3的幂,因数也都是3的幂,所以这里直接取Integer范围里面最大的3的幂,然后对n取余
public class Solution {
//知道了 n 的限制,我们现在可以推断出 n 的最大值,也就是 3 的幂,是 1162261467。
//由于3是质数,所以最大值的因数只能是3的次幂,所以如果最大值除以n余数为0,得到的就是3的幂
public boolean isPowerOfThree(int n) {
return n > 0 && 1162261467 % n == 0;
}
}
下一个方法,用toString()方法,将n转换成3进制数
然后判断这个3进制数,是否是10000…这种形式,用正则表达式判断,这里正则表达式又忘了,不过这个东西一看就会了
public class Solution {
public boolean isPowerOfThree(int n) {
//第一个方法用于将数n转换为以3为底的基数,并且以字符串的形式返回;
//第二个方法用于检查字符串中是否存在特定的字符串,
//这个正则表达式用来检查字符串是否以1开头,后跟0 或 多个 0 并且不包含任何其他值 $
return Integer.toString(n, 3).matches("^10*$");
}
}
下一个方法,也是数学
因为n = 3^x,那么求出x,判断x是不是一个整数,也就是求log以3位底,n的对数
然后因为java中有的是以10为底的对数,所以用公式转换一下
public class Solution {
//这个方法是纯数学计算,就是i = log3(n);java中有一个计算以10为低的对数,所以用公式变成:
//log10(n)/log10(3),判断是否结果是一个整数
public boolean isPowerOfThree(int n) {
return (Math.log10(n) / Math.log10(3)) % 1 == 0;
}
}
剑指 Offer 62. 圆圈中最后剩下的数字
题目描述
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
示例 1:
输入: n = 5, m = 3
输出: 3
示例 2:
输入: n = 10, m = 17
输出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
今天笔试遇到了约瑟夫环问题,来复习一下
首先很直观的模拟,很慢:
class Solution {
public int lastRemaining(int n, int m) {
List<Integer> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
list.add(i);
}
int idx = 0;
while (n > 1) {
idx = (idx + m - 1) % n;
list.remove(idx);
n--;
}
return list.get(0);
}
}
然后想规律
假设这个问题的答案是f(n, m)
那么第一次删除的位置就是m % n这个位置,然后第m%n+1这个位置就变成了f(n -1, m)这个问题的初始位置,也就是零位置
删除一个以后,问题变成了f(n - 1, m),假设这个问题的解是x
那么说明f(n, m)这个问题的答案应该是在m % n位置基础上,再移动x个位置
递归可以写,动态规划节省空间
class Solution {
public int lastRemaining(int n, int m) {
int pre = 0;
for(int i = 2; i <= n; i++){
int f = (m + pre) % i;
pre = f;
}
return pre;
}
}