因为要求额外空间复杂度为O(1),所以我们只能使用有限几个变量,来得到整个数组所在的城市距离首都的距离。因为数组paths[i]表示,i城市指向paths[i]城市,我们可以利用这个指向关系(next为下次要去的城市,last为当前城市。并且在往前遍历时,要记录回去的信息,即paths[next的值]=last的值,这样我们就可以再通过last和next往回走),一直往前遍历,直到next==paths[next],或者paths[next] < 0,我们便开始往回走,并且回走时,如果城市i距离首都为x,则给paths[i]赋值为-x。
然后得到了这个距离数组后,再通过判断距离数组的正负来统计距离(通过指向关系来进行循环计数)的个数。
- import java.util.Arrays;
-
- /**
- * @ProjectName: study3
- * @FileName: Ex1
- * @author:HWJ
- * @Data: 2023/9/14 22:30
- */
- public class Ex1 {
- public static void main(String[] args) {
- int[] paths = {9, 1, 4, 9, 0, 4, 8, 9, 0, 1};
- pathToDistance(paths);
- distanceToCount(paths);
- System.out.println(Arrays.toString(paths));
- }
-
- public static void pathToDistance(int[] paths) {
- int n = paths.length;
- int capital = -1;
- for (int start = 0; start < n; start++) {
- if (paths[start] == start) {
- capital = start;
- } else if (paths[start] > -1) {
- int last = start;
- int next = paths[last];
- while (paths[next] != next && paths[next] > -1) {
- int num = paths[next];
- paths[next] = last;
- last = next;
- next = num;
- }
- int i = paths[next] == next ? 0 : paths[next];
- while (last != start) {
- int num = paths[last];
- paths[last] = --i;
- last = num;
- }
- paths[last] = --i;
- }
- }
- paths[capital] = 0;
- }
-
- public static void distanceToCount(int[] paths){
- for (int i = 0; i < paths.length; i++) {
- int cur = paths[i];
- paths[i] = Math.max(paths[i], 0);
- while (cur <= 0){
- int next = paths[-cur];
- if (next < 0){
- paths[-cur] = 1;
- cur = next;
- }else {
- paths[-cur]++;
- break;
- }
- }
-
- }
- }
- }
一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:
每个孩子不管得分多少,起码分到一个糖果。
任意两个相邻的孩子之间,得分较多的孩子必须拿多一些糖果。
【进价】要求相邻的两个孩子如果得分相同,得到的糖果应该相同。
要求时间复杂度为O(N)
我们可以通过得分数组得到一个得分的折线图(即升降情况),然后通过从左向右遍历这个升降情况得到每个人应该分到的糖果数。然后通过从右向左遍历这个升降情况得到每个人应该分到的糖果数。然后对应求最大即为每个孩子的糖果数。遍历时要求升序糖果数++,如果降序或者保持不变,使糖果数变回1.
我们可以通过得分数组得到一个得分的折线图(即升降情况),然后通过从左向右遍历这个升降情况得到每个人应该分到的糖果数。然后通过从右向左遍历这个升降情况得到每个人应该分到的糖果数。然后对应求最大即为每个孩子的糖果数。遍历时要求升序糖果数++,如果降序使糖果数变回1,如果保持不变,则使糖果数保持不变。
- /**
- * @ProjectName: study3
- * @FileName: Ex2
- * @author:HWJ
- * @Data: 2023/9/15 0:07
- */
- public class Ex2 {
- public static void main(String[] args) {
- int[] scores = {1, 2, 2};
- System.out.println(candy1(scores));
- System.out.println(candy2(scores));
- }
-
- public static int candy1(int[] scores){
- int[] left = new int[scores.length];
- int[] right = new int[scores.length];
- left[0] = 1;
- for (int i = 1; i < scores.length; i++) {
- if(scores[i] > scores[i - 1]){
- left[i] = left[i - 1] + 1;
- }else {
- left[i] = 1;
- }
- }
- right[scores.length - 1] = 1;
- for (int i = scores.length - 2; i >= 1; i--) {
- if(scores[i] > scores[i + 1]){
- right[i] = right[i + 1] + 1;
- }else {
- right[i] = 1;
- }
- }
- int res = 0;
- for (int i = 0; i < scores.length; i++) {
- res += Math.max(left[i], right[i]);
- }
- return res;
- }
-
- public static int candy2(int[] scores){
- int[] left = new int[scores.length];
- int[] right = new int[scores.length];
- left[0] = 1;
- for (int i = 1; i < scores.length; i++) {
- if(scores[i] > scores[i - 1]){
- left[i] = left[i - 1] + 1;
- }else if (scores[i] < scores[i - 1]){
- left[i] = 1;
- }else {
- left[i] = left[i - 1];
- }
- }
- right[scores.length - 1] = 1;
- for (int i = scores.length - 2; i >= 1; i--) {
- if(scores[i] > scores[i + 1]){
- right[i] = right[i + 1] + 1;
- }else if (scores[i] < scores[i + 1]){
- right[i] = 1;
- }else {
- right[i] = right[i + 1];
- }
- }
- int res = 0;
- for (int i = 0; i < scores.length; i++) {
- res += Math.max(left[i], right[i]);
- }
- return res;
- }
- }
要求时间复杂度为O(N), 额外空间复杂度为O(1)。 实现特别困难。
第一种思路,列出所有可能性,然后在递归时得到所有可能性,然后不断汇总求最优解。
能获得最优解的可能性如下:
(1)x结点以下都被照亮(包含x结点),且x上不放灯。
(2)x结点以下都被照亮(包含x结点),且x上放灯。
(3)x结点以下都被照亮(不包含x结点),但x上放灯。(因为这种情况可能引出下一个最优解,在x的父上放灯,影响的结点更多)。
第二种思路,我们在传递的时候已知最优解需要的是什么信息,利用贪心加速常数时间。
比如当左孩子和右孩子,未被覆盖时,x上必须放灯,如果左孩子和右孩子,被覆盖且放灯,则x上一定不放灯。如果左孩子和右子,被覆盖但没放灯,则x未被覆盖。
- /**
- * @ProjectName: study3
- * @FileName: Ex3
- * @author:HWJ
- * @Data: 2023/9/15 0:16
- */
- public class Ex3 {
- public static void main(String[] args) {
-
- }
-
- public static class Node{
- Node left;
- Node right;
- }
-
- public static class ReturnData{
- public int unCovered;
- public int coveredNoCamera;
- public int coveredHasCamera;
-
- public ReturnData(int unCovered, int coveredNoCamera, int coveredHasCamera) {
- this.unCovered = unCovered;
- this.coveredNoCamera = coveredNoCamera;
- this.coveredHasCamera = coveredHasCamera;
- }
- }
-
- public static int getMin(Node head){
- ReturnData data = process(head);
- return Math.min(data.unCovered, Math.min(data.coveredHasCamera, data.coveredNoCamera));
- }
-
- public static ReturnData process(Node node){
- if (node == null){
- return new ReturnData(Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
- }
- ReturnData left = process(node.left);
- ReturnData right = process(node.right);
- int unCovered = left.coveredNoCamera + right.coveredNoCamera;
- int coveredNoCamera = Math.min(left.coveredHasCamera + right.coveredHasCamera,
- Math.min(left.coveredHasCamera + right.coveredNoCamera,
- left.coveredNoCamera + right.coveredHasCamera));
- int coveredHasCamera = Math.min(left.unCovered,
- Math.min(left.coveredHasCamera, left.coveredNoCamera)) +
- Math.min(right.unCovered,
- Math.min(right.coveredHasCamera, right.coveredNoCamera)) + 1;
- return new ReturnData(unCovered, coveredNoCamera, coveredHasCamera);
- }
-
- public enum Status{
- UNCOVERED, COVERED_NO_CAMERA, COVERED_HAS_CAMERA;
- }
-
- public static class ReturnData2{
- public Status status;
- public int cameras;
-
- public ReturnData2(Status status, int cameras) {
- this.status = status;
- this.cameras = cameras;
- }
- }
-
- public static int getMin2(Node head){
- ReturnData2 data = process2(head);
- return data.cameras + (data.status == Status.UNCOVERED ? 1 : 0);
- }
-
- public static ReturnData2 process2(Node node){
- if (node == null){
- return new ReturnData2(Status.COVERED_NO_CAMERA, 0);
- }
- ReturnData2 left = process2(node.left);
- ReturnData2 right = process2(node.right);
- int cameras = left.cameras + right.cameras;
- if (left.status == Status.UNCOVERED || right.status == Status.UNCOVERED){
- return new ReturnData2(Status.COVERED_HAS_CAMERA, cameras + 1);
- }
- if (left.status == Status.COVERED_HAS_CAMERA && right.status == Status.COVERED_HAS_CAMERA){
- return new ReturnData2(Status.COVERED_NO_CAMERA, cameras);
- }
- return new ReturnData2(Status.UNCOVERED, cameras);
- }
- }