2017.10.25 DP 解题报告

本文介绍了一道算法题的解决思路及DP实现方法,旨在找出经一次位翻转后的01串中最大长度的01交替子序列。通过动态规划记录不同状态下的最优解,最终得出翻转操作后能得到的最长子序列。

眼镜(glasses.c/cpp/pas)

3.1 题目描述

这只小动物找到了书中的力量,它几乎就要成功了,依据书中内容,它还缺一副眼镜。
于是它找到了一个01串,想要从中找到制造眼镜的材料。它希望找到这个01串的最长的子序列串(即不要求连续),这个子序列满足01交间的性质(01010…或10101…)。
但是在寻找之前,它想测试一下目前拥有的力量,于是它选择了一段连续的区间,将这个区间中的0变成1、1变成0,再在其中寻找最长01交间子序列串。
当然,它希望合适地运用仅一次自己的力量(但一定要使用),使得这个子序列串变得尽可能长。

3.2 输入格式

仅一行一个长为n的01字符串。

3.3 输出格式

输出一行一个整数表示答案。

3.4 样例输入

10000011

3.5 样例输出

5

3.6 样例解释

将其变为10011011,这个串中的满足条件的子序列串长度即为5,可以证明这是最长的长度。

3.7 数据范围与约定*

对于10%的数据,保证 n<=500。
对于30%的数据,保证 n<=5000。
对于100%的数据,保证n<=500000。

【解题报告】

原本是观察性质直接特判的,想了一个DP
dp[i][3][2]表示已经到了第i为,状态(区间左,区间中,区间右),下一位应该填0还是1

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define N 500010

char s[N];
int n,dp[N][6][2];

int main()
{
    freopen("glasses.in","r",stdin);
    freopen("glasses.out","w",stdout);
    scanf("%s",s+1);n=strlen(s+1);
    memset(dp,-inf,sizeof(dp));
    if(s[1]=='1')
    {
        dp[1][1][0]=1;
        dp[1][2][1]=1;
    }
    if(s[1]=='0')
    {
        dp[1][1][1]=1;
        dp[1][2][0]=1;
    }
    for(int i=2;i<=n;++i)
    {
        if(s[i]=='1')
        {
            dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][1][1]+1);
            dp[i][2][1]=max(dp[i-1][1][1],dp[i-1][1][0]+1);
            dp[i][2][1]=max(dp[i][2][1],max(dp[i-1][2][1],dp[i-1][2][0]+1));
            dp[i][3][0]=max(dp[i-1][2][0],dp[i-1][2][1]+1);
            dp[i][3][0]=max(dp[i][3][0],max(dp[i-1][3][0],dp[i-1][3][1]+1));
        }
        if(s[i]=='0')
        {
            dp[i][1][1]=max(dp[i-1][1][1],dp[i-1][1][0]+1);
            dp[i][2][0]=max(dp[i-1][1][0],dp[i-1][1][1]+1);
            dp[i][2][0]=max(dp[i][2][0],max(dp[i-1][2][0],dp[i-1][2][1]+1));
            dp[i][3][1]=max(dp[i-1][2][1],dp[i-1][2][0]+1);
            dp[i][3][1]=max(dp[i][3][1],max(dp[i-1][3][1],dp[i-1][3][0]+1));        
        }
    }
    int ans=-inf;
    for(int i=2;i<=3;++i)
    for(int j=0;j<=1;++j) ans=max(ans,dp[n][i][j]);
    printf("%d\n",ans);
    return 0;
}
package com.weishitech.jtwzjiaotongcx.fragment.lilv; import android.app.AlertDialog; import android.text.Html; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import android.widget.Toast; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.weishitech.jtwzjiaotongcx.R; import com.weishitech.jtwzjiaotongcx.adtakubase.activity.BaseBindActivity; import com.weishitech.jtwzjiaotongcx.bean.Question; import com.weishitech.jtwzjiaotongcx.databinding.ActivityDetailsBinding; import com.weishitech.jtwzjiaotongcx.fragment.Adapter.AnswerStatusAdapter; import com.weishitech.jtwzjiaotongcx.utils.OnMultiClickListener; import java.lang.reflect.Type; import java.util.List; public class AnswerDetailActivity extends BaseBindActivity<ActivityDetailsBinding> { private List<Question.DataBean> questionList; private RecyclerView recyclerView; private AnswerStatusAdapter adapter; @Override protected void init() { mBinding.ivBack.setOnClickListener(new OnMultiClickListener() { @Override public void onMultiClick(View v) { finish(); } }); recyclerView = mBinding.rv; recyclerView.setLayoutManager(new GridLayoutManager(this, 10)); // 每行10个题号 parseData(); setupAdapter(); } private void parseData() { String json = getIntent().getStringExtra("questionList"); Log.d("AnswerDetail", "Received JSON: " + json); if (json == null || json.isEmpty()) { Toast.makeText(this, "数据加载失败", Toast.LENGTH_SHORT).show(); finish(); return; } Type type = new TypeToken<List<Question.DataBean>>(){}.getType(); questionList = new Gson().fromJson(json, type); } private void setupAdapter() { adapter = new AnswerStatusAdapter(questionList, position -> { showQuestionDetailDialog(position); }); recyclerView.setAdapter(adapter); } private void showQuestionDetailDialog(int position) { Question.DataBean q = questionList.get(position); AlertDialog.Builder builder = new AlertDialog.Builder(this); View dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_question_detail, null); builder.setView(dialogView); TextView tvTitle = dialogView.findViewById(R.id.tv_question_title); TextView tvUserAnswer = dialogView.findViewById(R.id.tv_user_answer); TextView tvCorrectAnswer = dialogView.findViewById(R.id.tv_correct_answer); TextView tvAnalysis = dialogView.findViewById(R.id.tv_analysis); TextView btnClose = dialogView.findViewById(R.id.btn_close); tvTitle.setText((position + 1) + ". " + q.getTitle()); String userAns = q.getShowAnswer(); if (!userAns.isEmpty()) { tvUserAnswer.setText(userAns); } else { tvUserAnswer.setText("未作答"); } tvCorrectAnswer.setText(q.getAnswer()); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { tvAnalysis.setText(Html.fromHtml(q.getAnalysis(), Html.FROM_HTML_MODE_LEGACY)); } else { tvAnalysis.setText(Html.fromHtml(q.getAnalysis())); } AlertDialog dialog = builder.create(); btnClose.setOnClickListener(v -> dialog.dismiss()); dialog.show(); } }package com.weishitech.jtwzjiaotongcx.bean; import com.hfd.common.model.PublicData; import java.util.List; // Question.java public class Question extends PublicData { private List<DataBean> data; public List<DataBean> getData() { return data; } public void setData(List<DataBean> data) { this.data = data; } public static class DataBean { /** * id : 147 * questionId : 30119 * title : 当事人有下列哪种行为,要承担交通事故全部责任? * rank : 1 * type : 1 * op1 : A、在高速公路上撞伤行人的 * op2 : B、在路口直行与转弯车辆刮碰的 * op3 : C、在快车道与摩托车刮碰的 * op4 : D、发生事故后故意损坏、伪造现场、毁灭证据的 * titleType : 1 * titlePic : * createTime : 2025-07-30 14:26:28 * updateTime : 2025-07-30 14:26:28 */ // { // "question": "在路口遇这种情形要减速让行。", // "answer": "1", // "item1": "正确", // "item2": "错误", // "item3": "", // "item4": "", // "explains": "当驾车在路口遇到图中减速让行标志时,机动车应主动减速让行。\r<br/><p><img src=http://tp.mnks.cn/tp_177.jpg>\r<br/>减速让行\r<br/><img src=http://tp.mnks.cn/tp_176.jpg>\r<br/>停车让行\r<br/></p>", // "url": "https://aimgs.oss-cn-shenzhen.aliyuncs.com/jztk/2017/c1c2subject1/4750.jpg" // }, private int id; private int questionId; private String title; private int rank; private int type; private String op1; private String op2; private String op3; private String op4; private int titleType; private String titlePic; private String createTime; private String updateTime; private boolean isSelectA;//选中 private boolean isSelectB; private boolean isSelectC; private boolean isSelectD; private String showAnswer = "";//确认答案 private String answer; private String analysis; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getQuestionId() { return questionId; } public void setQuestionId(int questionId) { this.questionId = questionId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getOp1() { return op1; } public void setOp1(String op1) { this.op1 = op1; } public String getOp2() { return op2; } public void setOp2(String op2) { this.op2 = op2; } public String getOp3() { return op3; } public void setOp3(String op3) { this.op3 = op3; } public String getOp4() { return op4; } public void setOp4(String op4) { this.op4 = op4; } public int getTitleType() { return titleType; } public void setTitleType(int titleType) { this.titleType = titleType; } public String getTitlePic() { return titlePic; } public void setTitlePic(String titlePic) { this.titlePic = titlePic; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getUpdateTime() { return updateTime; } public void setUpdateTime(String updateTime) { this.updateTime = updateTime; } public boolean isSelectA() { return isSelectA; } public void setSelectA(boolean selectA) { isSelectA = selectA; } public boolean isSelectB() { return isSelectB; } public void setSelectB(boolean selectB) { isSelectB = selectB; } public boolean isSelectC() { return isSelectC; } public void setSelectC(boolean selectC) { isSelectC = selectC; } public boolean isSelectD() { return isSelectD; } public void setSelectD(boolean selectD) { isSelectD = selectD; } public String getShowAnswer() { return showAnswer; } public void setShowAnswer(String showAnswer) { this.showAnswer = showAnswer; } public String getAnswer() { return answer; } public void setAnswer(String answer) { this.answer = answer; } public String getAnalysis() { return analysis; } public void setAnalysis(String analysis) { this.analysis = analysis; } } } package com.weishitech.jtwzjiaotongcx.fragment.Adapter; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.weishitech.jtwzjiaotongcx.R; import com.weishitech.jtwzjiaotongcx.bean.Question; import java.util.List; public class AnswerStatusAdapter extends RecyclerView.Adapter<AnswerStatusAdapter.ViewHolder> { private final List<Question.DataBean> questions; private final OnItemClickListener listener; public interface OnItemClickListener { void onItemClick(int position); } public AnswerStatusAdapter(List<Question.DataBean> questions, OnItemClickListener listener) { this.questions = questions; this.listener = listener; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { Button button = new Button(parent.getContext()); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 0, // width: 权重分配 180, 1.0f ); params.setMargins(8, 8, 8, 8); button.setLayoutParams(params); button.setTextSize(14); button.setAllCaps(false); // 关闭大写转换 return new ViewHolder(button); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Button button = holder.button; Question.DataBean data = questions.get(position); String userAnswer = data.getShowAnswer(); button.setText(String.valueOf(position + 1)); if (userAnswer.isEmpty()) { // 未答:白底黑框 button.setBackgroundColor(Color.WHITE); button.setTextColor(Color.BLACK); button.setBackgroundResource(R.drawable.bg_answer_unanswered); } else if (userAnswer.equals(data.getAnswer())) { // 正确:蓝底白字圆角 button.setBackgroundResource(R.drawable.bg_answer_correct); button.setTextColor(Color.WHITE); } else { // 错误:红底白字圆角 button.setBackgroundResource(R.drawable.bg_answer_wrong); button.setTextColor(Color.WHITE); } button.setOnClickListener(v -> listener.onItemClick(position)); } @Override public int getItemCount() { return questions.size(); } static class ViewHolder extends RecyclerView.ViewHolder { Button button; public ViewHolder(Button button) { super(button); this.button = button; } } } 没有显示数据
最新发布
12-31
你已经做了很多工作,但 `RecyclerView` 仍然 **没有显示数据**。我们来一步一步 **精准排查并彻底解决问题**。 --- ## 🔍 当前问题总结 - ✅ 数据从 `TestActivity` 通过 `Gson.toJson(list)` 发出 - ✅ `AnswerDetailActivity` 接收到 JSON 字符串 - ✅ 成功解析为 `List<Question.DataBean>` - ❌ 但是 `RecyclerView` 没有显示任何按钮(空白) --- ## ✅ 根本原因锁定:动态创建 `Button` 在 `RecyclerView` 中严重失效! 你在 `AnswerStatusAdapter.onCreateViewHolder()` 中: ```java Button button = new Button(parent.getContext()); ``` 这是导致 **不显示的根本原因!** > ⚠️ Android 的 `RecyclerView` 对动态添加的 View 支持极差: > > - 它不会正确测量 `new Button(...)` > - `0dp width + weight` 在非 `LinearLayout` 下无效 > - `RecyclerView` 内部使用的是 `ViewGroup`,不是 `LinearLayout`,所以 `weight` 不生效 > - 导致每个 `Button` 实际宽度为 0 → 看不见! --- # ✅ 解决方案:立即改用 XML 布局文件加载 item! --- ## ✅ 第一步:创建 `res/layout/item_answer_number.xml` ```xml <!-- res/layout/item_answer_number.xml --> <?xml version="1.0" encoding="utf-8"?> <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/btn_number" android:layout_width="0dp" android:layout_height="64dp" android:layout_margin="6dp" android:background="@drawable/bg_answer_unanswered" android:gravity="center" android:paddingLeft="0dp" android:paddingRight="0dp" android:textColor="#000000" android:textSize="15sp" android:textStyle="bold" android:clickable="true" android:focusable="true" /> ``` > 注意:`layout_width="0dp"` 是为了配合 `GridLayoutManager` 平分空间。 --- ## ✅ 第二步:修改 `AnswerStatusAdapter.java` ### 替换整个类如下: ```java package com.weishitech.jtwzjiaotongcx.fragment.Adapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.weishitech.jtwzjiaotongcx.R; import com.weishitech.jtwzjiaotongcx.bean.Question; import java.util.List; public class AnswerStatusAdapter extends RecyclerView.Adapter<AnswerStatusAdapter.ViewHolder> { private final List<Question.DataBean> questions; private final OnItemClickListener listener; public interface OnItemClickListener { void onItemClick(int position); } public AnswerStatusAdapter(List<Question.DataBean> questions, OnItemClickListener listener) { this.questions = questions; this.listener = listener; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // ✅ 使用 LayoutInflater 加载 XML 布局 View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_answer_number, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Question.DataBean data = questions.get(position); String userAnswer = data.getShowAnswer(); holder.button.setText(String.valueOf(position + 1)); if (userAnswer.isEmpty()) { // 未答:白底黑框 holder.button.setBackgroundResource(R.drawable.bg_answer_unanswered); holder.button.setTextColor(0xFF000000); // 黑色 } else if (userAnswer.equals(data.getAnswer())) { // 正确:蓝色圆角 holder.button.setBackgroundResource(R.drawable.bg_answer_correct); holder.button.setTextColor(0xFFFFFFFF); // 白色 } else { // 错误:红色圆角 holder.button.setBackgroundResource(R.drawable.bg_answer_wrong); holder.button.setTextColor(0xFFFFFFFF); // 白色 } holder.button.setOnClickListener(v -> listener.onItemClick(position)); } @Override public int getItemCount() { return questions.size(); } static class ViewHolder extends RecyclerView.ViewHolder { Button button; public ViewHolder(View itemView) { super(itemView); button = itemView.findViewById(R.id.btn_number); } } } ``` --- ## ✅ 第三步:确认你的 drawable 资源存在 ### ✅ 文件必须存在且命名正确: #### `res/drawable/bg_answer_unanswered.xml` ```xml <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#FFFFFF" /> <stroke android:width="2dp" android:color="#000000" /> <corners android:radius="8dp" /> </shape> ``` #### `res/drawable/bg_answer_correct.xml` ```xml <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#007AFF" /> <corners android:radius="8dp" /> </shape> ``` #### `res/drawable/bg_answer_wrong.xml` ```xml <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="#FF3B30" /> <corners android:radius="8dp" /> </shape> ``` --- ## ✅ 第四步:确保 `activity_details.xml` 中 RecyclerView 高度不是 0 ```xml <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent" <!-- 必须 match_parent --> android:layout_marginTop="10dp" /> ``` 如果你父布局是 `LinearLayout`,也要确保它能撑开。 --- ## ✅ 第五步:加日志验证数据是否真的传进来了 在 `parseData()` 方法中加入: ```java private void parseData() { String json = getIntent().getStringExtra("questionList"); Log.d("AnswerDetail", "JSON length: " + (json != null ? json.length() : "null")); Log.d("AnswerDetail", "Raw JSON: " + json); if (json == null || json.isEmpty()) { Toast.makeText(this, "数据加载失败", Toast.LENGTH_SHORT).show(); finish(); return; } Type type = new TypeToken<List<Question.DataBean>>(){}.getType(); questionList = new Gson().fromJson(json, type); Log.d("AnswerDetail", "✅ 解析成功,题目数量: " + (questionList != null ? questionList.size() : "null")); if (questionList == null || questionList.isEmpty()) { Toast.makeText(this, "解析为空", Toast.LENGTH_SHORT).show(); finish(); return; } } ``` > 📱 打开 Logcat 过滤 `AnswerDetail`,你应该看到类似: > > ``` > JSON length: 12345 > ✅ 解析成功,题目数量: 100 > ``` --- ## ✅ 第六步:检查 `TestActivity` 是否真的传递了数据 在 `confirmSubmit()` 中交卷前打印: ```java Log.d("TestActivity", "准备跳转,list size = " + list.size()); Log.d("TestActivity", "Gson JSON = " + new Gson().toJson(list).substring(0, 100) + "..."); ``` 确保不是空数组或 null。 --- ## ✅ 第七步:清理项目 + 重新运行 有时候旧编译缓存会导致资源找不到: - `Build > Clean Project` - `Build > Rebuild Project` - 卸载 App 后重新安装 --- ## ✅ 最终效果验证流程 | 步骤 | 是否完成 | |------|--------| | ✅ 创建 `item_answer_number.xml` | ✔️ | | ✅ 修改 Adapter 使用 `inflate` 加载布局 | ✔️ | | ✅ 删除 `new Button()` 动态创建方式 | ✔️ | | ✅ 确保 `RecyclerView` 高度为 `match_parent` | ✔️ | | ✅ 添加日志确认数据已接收和解析 | ✔️ | | ✅ 检查 drawable 资源是否存在 | ✔️ | | ✅ 清理重建项目 | ✔️ | --- ✅ 完成以上步骤后,你会看到一个 10×10 的题号网格,每道题根据答题状态显示不同颜色,并可点击查看详情。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值